@spaceflow/core 0.1.3 → 0.2.0
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/dist/index.js +2501 -3301
- package/dist/index.js.map +1 -1
- package/package.json +2 -13
- package/src/config/config-loader.ts +5 -6
- package/src/config/config-reader.service.ts +6 -11
- package/src/config/config-reader.ts +75 -0
- package/src/config/index.ts +4 -1
- package/src/config/load-env.ts +15 -0
- package/src/config/schema-generator.service.ts +0 -2
- package/src/config/spaceflow.config.ts +7 -20
- package/src/extension-system/define-extension.ts +25 -0
- package/src/extension-system/extension.interface.ts +0 -63
- package/src/extension-system/index.ts +5 -0
- package/src/extension-system/types.ts +201 -0
- package/src/index.ts +15 -18
- package/src/shared/claude-setup/claude-setup.service.ts +3 -8
- package/src/shared/claude-setup/index.ts +0 -1
- package/src/shared/feishu-sdk/feishu-sdk.service.ts +33 -21
- package/src/shared/feishu-sdk/fieshu-card.service.ts +9 -11
- package/src/shared/feishu-sdk/index.ts +0 -1
- package/src/shared/git-provider/git-provider.service.ts +1 -6
- package/src/shared/git-provider/index.ts +0 -1
- package/src/shared/git-sdk/git-sdk.service.ts +0 -2
- package/src/shared/git-sdk/index.ts +0 -1
- package/src/shared/llm-proxy/adapters/claude-code.adapter.spec.ts +15 -32
- package/src/shared/llm-proxy/adapters/claude-code.adapter.ts +5 -6
- package/src/shared/llm-proxy/adapters/open-code.adapter.ts +1 -3
- package/src/shared/llm-proxy/adapters/openai.adapter.spec.ts +7 -21
- package/src/shared/llm-proxy/adapters/openai.adapter.ts +1 -3
- package/src/shared/llm-proxy/index.ts +0 -1
- package/src/shared/llm-proxy/interfaces/config.interface.ts +8 -0
- package/src/shared/llm-proxy/llm-proxy.service.spec.ts +91 -68
- package/src/shared/llm-proxy/llm-proxy.service.ts +5 -8
- package/src/shared/mcp/index.ts +1 -33
- package/src/shared/output/index.ts +0 -1
- package/src/shared/output/output.service.ts +43 -13
- package/src/shared/rspack-config/rspack-config.ts +0 -6
- package/src/shared/storage/index.ts +0 -1
- package/src/shared/storage/storage.service.ts +16 -8
- package/src/shared/storage/types.ts +0 -44
- package/src/shared/verbose/index.ts +15 -0
- package/src/app.module.ts +0 -18
- package/src/config/config-reader.module.ts +0 -16
- package/src/shared/claude-setup/claude-setup.module.ts +0 -8
- package/src/shared/feishu-sdk/feishu-sdk.module.ts +0 -77
- package/src/shared/git-provider/git-provider.module.ts +0 -73
- package/src/shared/git-sdk/git-sdk.module.ts +0 -8
- package/src/shared/llm-proxy/llm-proxy.module.ts +0 -140
- package/src/shared/output/output.module.ts +0 -9
- package/src/shared/storage/storage.module.ts +0 -150
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { EventEmitter2 } from "@nestjs/event-emitter";
|
|
1
|
+
import { EventEmitter } from "events";
|
|
3
2
|
import * as lark from "@larksuiteoapi/node-sdk";
|
|
4
3
|
import {
|
|
5
4
|
FeishuModuleOptions,
|
|
6
|
-
FEISHU_MODULE_OPTIONS,
|
|
7
5
|
FeishuUser,
|
|
8
6
|
GetUserParams,
|
|
9
7
|
FEISHU_CARD_ACTION_TRIGGER,
|
|
@@ -15,12 +13,39 @@ import {
|
|
|
15
13
|
/**
|
|
16
14
|
* 飞书 API 服务
|
|
17
15
|
*/
|
|
18
|
-
|
|
19
|
-
export class FeishuSdkService implements OnModuleInit, OnModuleDestroy {
|
|
16
|
+
export class FeishuSdkService {
|
|
20
17
|
protected readonly client: lark.Client;
|
|
18
|
+
protected readonly eventEmitter: EventEmitter;
|
|
19
|
+
private eventDispatcher: lark.EventDispatcher | null = null;
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
constructor(protected readonly options: FeishuModuleOptions) {
|
|
22
|
+
this.eventEmitter = new EventEmitter();
|
|
23
|
+
this.client = new lark.Client({
|
|
24
|
+
appId: options.appId,
|
|
25
|
+
appSecret: options.appSecret,
|
|
26
|
+
appType: options.appType === "store" ? lark.AppType.ISV : lark.AppType.SelfBuild,
|
|
27
|
+
domain: options.domain === "lark" ? lark.Domain.Lark : lark.Domain.Feishu,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
this.initEventDispatcher();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 注册事件监听器
|
|
35
|
+
*/
|
|
36
|
+
on(eventName: string, listener: (...args: any[]) => void): void {
|
|
37
|
+
this.eventEmitter.on(eventName, listener);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 移除事件监听器
|
|
42
|
+
*/
|
|
43
|
+
off(eventName: string, listener: (...args: any[]) => void): void {
|
|
44
|
+
this.eventEmitter.off(eventName, listener);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private initEventDispatcher(): void {
|
|
48
|
+
this.eventDispatcher = new lark.EventDispatcher({
|
|
24
49
|
encryptKey: "encrypt key",
|
|
25
50
|
}).register<CardEvents>({
|
|
26
51
|
[FEISHU_CARD_ACTION_TRIGGER]: async (data) => {
|
|
@@ -41,23 +66,10 @@ export class FeishuSdkService implements OnModuleInit, OnModuleDestroy {
|
|
|
41
66
|
});
|
|
42
67
|
}
|
|
43
68
|
|
|
44
|
-
|
|
69
|
+
destroy(): void {
|
|
45
70
|
this.eventEmitter.removeAllListeners();
|
|
46
71
|
}
|
|
47
72
|
|
|
48
|
-
constructor(
|
|
49
|
-
@Inject(FEISHU_MODULE_OPTIONS)
|
|
50
|
-
protected readonly options: FeishuModuleOptions,
|
|
51
|
-
protected readonly eventEmitter: EventEmitter2,
|
|
52
|
-
) {
|
|
53
|
-
this.client = new lark.Client({
|
|
54
|
-
appId: options.appId,
|
|
55
|
-
appSecret: options.appSecret,
|
|
56
|
-
appType: options.appType === "store" ? lark.AppType.ISV : lark.AppType.SelfBuild,
|
|
57
|
-
domain: options.domain === "lark" ? lark.Domain.Lark : lark.Domain.Feishu,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
73
|
/**
|
|
62
74
|
* 验证飞书配置
|
|
63
75
|
*/
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Injectable } from "@nestjs/common";
|
|
2
1
|
import { FeishuSdkService } from "./feishu-sdk.service";
|
|
3
2
|
import {
|
|
4
3
|
SendCardParams,
|
|
@@ -8,25 +7,24 @@ import {
|
|
|
8
7
|
CardContent,
|
|
9
8
|
type CardActionTriggerCallback,
|
|
10
9
|
} from "./types";
|
|
11
|
-
import { OnEvent, type EventEmitter2 } from "@nestjs/event-emitter";
|
|
12
10
|
import { FEISHU_CARD_ACTION_TRIGGER } from "./types";
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* 飞书卡片消息服务
|
|
16
14
|
* 提供卡片消息的发送、回复、更新功能
|
|
17
15
|
*/
|
|
18
|
-
@Injectable()
|
|
19
16
|
export class FeishuCardService {
|
|
20
|
-
constructor(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
constructor(protected readonly feishuSdkService: FeishuSdkService) {
|
|
18
|
+
// 监听卡片动作触发事件
|
|
19
|
+
feishuSdkService.on(FEISHU_CARD_ACTION_TRIGGER, (event) => {
|
|
20
|
+
this.handleCardActionTrigger(event);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const event_hook = event.header.event_type ?? event.event.action.tag;
|
|
24
|
+
async handleCardActionTrigger(event: CardActionTriggerCallback): Promise<void> {
|
|
25
|
+
const _eventHook = event.header.event_type ?? event.event.action.tag;
|
|
28
26
|
|
|
29
|
-
// console.log(
|
|
27
|
+
// console.log(_eventHook);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
/**
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Inject, Injectable } from "@nestjs/common";
|
|
2
1
|
import type {
|
|
3
2
|
GitProvider,
|
|
4
3
|
LockBranchOptions,
|
|
@@ -6,7 +5,6 @@ import type {
|
|
|
6
5
|
} from "./git-provider.interface";
|
|
7
6
|
import {
|
|
8
7
|
type GitProviderModuleOptions,
|
|
9
|
-
GIT_PROVIDER_MODULE_OPTIONS,
|
|
10
8
|
type BranchProtection,
|
|
11
9
|
type CreateBranchProtectionOption,
|
|
12
10
|
type EditBranchProtectionOption,
|
|
@@ -36,13 +34,10 @@ import { GitlabAdapter } from "./adapters/gitlab.adapter";
|
|
|
36
34
|
* Git Provider 统一服务
|
|
37
35
|
* 根据配置的 provider 类型代理到对应的适配器实现
|
|
38
36
|
*/
|
|
39
|
-
@Injectable()
|
|
40
37
|
export class GitProviderService implements GitProvider {
|
|
41
38
|
protected readonly adapter: GitProvider;
|
|
42
39
|
|
|
43
|
-
constructor(
|
|
44
|
-
@Inject(GIT_PROVIDER_MODULE_OPTIONS) protected readonly options: GitProviderModuleOptions,
|
|
45
|
-
) {
|
|
40
|
+
constructor(protected readonly options: GitProviderModuleOptions) {
|
|
46
41
|
this.adapter = this.createAdapter(options);
|
|
47
42
|
}
|
|
48
43
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { Injectable } from "@nestjs/common";
|
|
2
1
|
import { spawn, execSync } from "child_process";
|
|
3
2
|
import type { GitCommit, GitChangedFile, GitDiffFile, GitRunOptions } from "./git-sdk.types";
|
|
4
3
|
import { mapGitStatus, parseDiffText } from "./git-sdk-diff.utils";
|
|
5
4
|
|
|
6
|
-
@Injectable()
|
|
7
5
|
export class GitSdkService {
|
|
8
6
|
protected readonly defaultOptions: GitRunOptions = {
|
|
9
7
|
cwd: process.cwd(),
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import { vi, type
|
|
2
|
-
import { Test, TestingModule } from "@nestjs/testing";
|
|
1
|
+
import { vi, type Mock } from "vitest";
|
|
3
2
|
import { ClaudeCodeAdapter } from "./claude-code.adapter";
|
|
4
|
-
import { ClaudeSetupService } from "../../claude-setup";
|
|
5
3
|
import { LlmStreamEvent } from "../interfaces";
|
|
6
4
|
|
|
7
5
|
vi.mock("@anthropic-ai/claude-agent-sdk", () => ({
|
|
8
6
|
query: vi.fn(),
|
|
9
7
|
}));
|
|
10
8
|
|
|
9
|
+
vi.mock("../../claude-setup", () => ({
|
|
10
|
+
ClaudeSetupService: class MockClaudeSetupService {
|
|
11
|
+
configure = vi.fn().mockResolvedValue(undefined);
|
|
12
|
+
backup = vi.fn().mockResolvedValue(undefined);
|
|
13
|
+
restore = vi.fn().mockResolvedValue(undefined);
|
|
14
|
+
withTemporaryConfig = vi.fn();
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
|
|
11
18
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
12
19
|
|
|
13
20
|
describe("ClaudeAdapter", () => {
|
|
14
21
|
let adapter: ClaudeCodeAdapter;
|
|
15
|
-
let claudeSetupService: Mocked<ClaudeSetupService>;
|
|
16
22
|
|
|
17
23
|
const mockConfig = {
|
|
18
24
|
claudeCode: {
|
|
@@ -21,24 +27,9 @@ describe("ClaudeAdapter", () => {
|
|
|
21
27
|
},
|
|
22
28
|
};
|
|
23
29
|
|
|
24
|
-
beforeEach(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
backup: vi.fn().mockResolvedValue(undefined),
|
|
28
|
-
restore: vi.fn().mockResolvedValue(undefined),
|
|
29
|
-
withTemporaryConfig: vi.fn(),
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
33
|
-
providers: [
|
|
34
|
-
ClaudeCodeAdapter,
|
|
35
|
-
{ provide: "LLM_PROXY_CONFIG", useValue: mockConfig },
|
|
36
|
-
{ provide: ClaudeSetupService, useValue: mockSetup },
|
|
37
|
-
],
|
|
38
|
-
}).compile();
|
|
39
|
-
|
|
40
|
-
adapter = module.get<ClaudeCodeAdapter>(ClaudeCodeAdapter);
|
|
41
|
-
claudeSetupService = module.get(ClaudeSetupService);
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
vi.clearAllMocks();
|
|
32
|
+
adapter = new ClaudeCodeAdapter(mockConfig as any);
|
|
42
33
|
});
|
|
43
34
|
|
|
44
35
|
it("should be defined", () => {
|
|
@@ -51,15 +42,8 @@ describe("ClaudeAdapter", () => {
|
|
|
51
42
|
expect(adapter.isConfigured()).toBe(true);
|
|
52
43
|
});
|
|
53
44
|
|
|
54
|
-
it("should return false if claude config is missing",
|
|
55
|
-
const
|
|
56
|
-
providers: [
|
|
57
|
-
ClaudeCodeAdapter,
|
|
58
|
-
{ provide: "LLM_PROXY_CONFIG", useValue: {} },
|
|
59
|
-
{ provide: ClaudeSetupService, useValue: { configure: vi.fn() } },
|
|
60
|
-
],
|
|
61
|
-
}).compile();
|
|
62
|
-
const unconfiguredAdapter = module.get<ClaudeCodeAdapter>(ClaudeCodeAdapter);
|
|
45
|
+
it("should return false if claude config is missing", () => {
|
|
46
|
+
const unconfiguredAdapter = new ClaudeCodeAdapter({} as any);
|
|
63
47
|
expect(unconfiguredAdapter.isConfigured()).toBe(false);
|
|
64
48
|
});
|
|
65
49
|
});
|
|
@@ -79,7 +63,6 @@ describe("ClaudeAdapter", () => {
|
|
|
79
63
|
events.push(event);
|
|
80
64
|
}
|
|
81
65
|
|
|
82
|
-
expect(claudeSetupService.configure).toHaveBeenCalled();
|
|
83
66
|
expect(query).toHaveBeenCalledWith(
|
|
84
67
|
expect.objectContaining({
|
|
85
68
|
prompt: "hello",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Injectable, Inject } from "@nestjs/common";
|
|
2
1
|
import { query, type SpawnOptions } from "@anthropic-ai/claude-agent-sdk";
|
|
3
2
|
import { spawn } from "child_process";
|
|
4
3
|
import type { LlmAdapter } from "./llm-adapter.interface";
|
|
@@ -12,14 +11,14 @@ import type {
|
|
|
12
11
|
import { ClaudeSetupService } from "../../claude-setup";
|
|
13
12
|
import { shouldLog } from "../../verbose";
|
|
14
13
|
|
|
15
|
-
@Injectable()
|
|
16
14
|
export class ClaudeCodeAdapter implements LlmAdapter {
|
|
17
15
|
readonly name = "claude-code";
|
|
16
|
+
private readonly claudeSetupService: ClaudeSetupService;
|
|
18
17
|
|
|
19
|
-
constructor(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
constructor(private readonly config: LlmProxyConfig) {
|
|
19
|
+
// 创建 ClaudeSetupService 实例,传入 LLM 配置
|
|
20
|
+
this.claudeSetupService = new ClaudeSetupService(config);
|
|
21
|
+
}
|
|
23
22
|
|
|
24
23
|
isConfigured(): boolean {
|
|
25
24
|
return !!this.config.claudeCode;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Injectable, Inject } from "@nestjs/common";
|
|
2
1
|
import { createOpencode } from "@opencode-ai/sdk";
|
|
3
2
|
import type { LlmAdapter } from "./llm-adapter.interface";
|
|
4
3
|
import type {
|
|
@@ -11,11 +10,10 @@ import type {
|
|
|
11
10
|
} from "../interfaces";
|
|
12
11
|
import { shouldLog } from "../../verbose";
|
|
13
12
|
|
|
14
|
-
@Injectable()
|
|
15
13
|
export class OpenCodeAdapter implements LlmAdapter {
|
|
16
14
|
readonly name = "open-code";
|
|
17
15
|
|
|
18
|
-
constructor(
|
|
16
|
+
constructor(private readonly config: LlmProxyConfig) {}
|
|
19
17
|
|
|
20
18
|
isConfigured(): boolean {
|
|
21
19
|
return !!this.config.openCode;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { vi, type Mock } from "vitest";
|
|
2
|
-
import { Test, TestingModule } from "@nestjs/testing";
|
|
3
2
|
import { OpenAIAdapter } from "./openai.adapter";
|
|
4
3
|
import OpenAI from "openai";
|
|
5
4
|
|
|
@@ -17,7 +16,8 @@ describe("OpenAIAdapter", () => {
|
|
|
17
16
|
},
|
|
18
17
|
};
|
|
19
18
|
|
|
20
|
-
beforeEach(
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.clearAllMocks();
|
|
21
21
|
mockOpenAIInstance = {
|
|
22
22
|
chat: {
|
|
23
23
|
completions: {
|
|
@@ -28,12 +28,7 @@ describe("OpenAIAdapter", () => {
|
|
|
28
28
|
(OpenAI as unknown as Mock).mockImplementation(function () {
|
|
29
29
|
return mockOpenAIInstance;
|
|
30
30
|
});
|
|
31
|
-
|
|
32
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
33
|
-
providers: [OpenAIAdapter, { provide: "LLM_PROXY_CONFIG", useValue: mockConfig }],
|
|
34
|
-
}).compile();
|
|
35
|
-
|
|
36
|
-
adapter = module.get<OpenAIAdapter>(OpenAIAdapter);
|
|
31
|
+
adapter = new OpenAIAdapter(mockConfig as any);
|
|
37
32
|
});
|
|
38
33
|
|
|
39
34
|
it("should be defined", () => {
|
|
@@ -46,11 +41,8 @@ describe("OpenAIAdapter", () => {
|
|
|
46
41
|
expect(adapter.isConfigured()).toBe(true);
|
|
47
42
|
});
|
|
48
43
|
|
|
49
|
-
it("should return false if openai config is missing",
|
|
50
|
-
const
|
|
51
|
-
providers: [OpenAIAdapter, { provide: "LLM_PROXY_CONFIG", useValue: {} }],
|
|
52
|
-
}).compile();
|
|
53
|
-
const unconfiguredAdapter = module.get<OpenAIAdapter>(OpenAIAdapter);
|
|
44
|
+
it("should return false if openai config is missing", () => {
|
|
45
|
+
const unconfiguredAdapter = new OpenAIAdapter({} as any);
|
|
54
46
|
expect(unconfiguredAdapter.isConfigured()).toBe(false);
|
|
55
47
|
});
|
|
56
48
|
});
|
|
@@ -156,10 +148,7 @@ describe("OpenAIAdapter", () => {
|
|
|
156
148
|
});
|
|
157
149
|
|
|
158
150
|
it("should yield error when openai not configured", async () => {
|
|
159
|
-
const
|
|
160
|
-
providers: [OpenAIAdapter, { provide: "LLM_PROXY_CONFIG", useValue: {} }],
|
|
161
|
-
}).compile();
|
|
162
|
-
const unconfigured = module.get<OpenAIAdapter>(OpenAIAdapter);
|
|
151
|
+
const unconfigured = new OpenAIAdapter({} as any);
|
|
163
152
|
const events: any[] = [];
|
|
164
153
|
for await (const event of unconfigured.chatStream([{ role: "user", content: "hi" }] as any)) {
|
|
165
154
|
events.push(event);
|
|
@@ -176,10 +165,7 @@ describe("OpenAIAdapter", () => {
|
|
|
176
165
|
});
|
|
177
166
|
|
|
178
167
|
it("should throw when openai not configured for chat", async () => {
|
|
179
|
-
const
|
|
180
|
-
providers: [OpenAIAdapter, { provide: "LLM_PROXY_CONFIG", useValue: {} }],
|
|
181
|
-
}).compile();
|
|
182
|
-
const unconfigured = module.get<OpenAIAdapter>(OpenAIAdapter);
|
|
168
|
+
const unconfigured = new OpenAIAdapter({} as any);
|
|
183
169
|
await expect(unconfigured.chat([{ role: "user", content: "hi" }] as any)).rejects.toThrow(
|
|
184
170
|
"未配置 openai",
|
|
185
171
|
);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Injectable, Inject } from "@nestjs/common";
|
|
2
1
|
import OpenAI from "openai";
|
|
3
2
|
import type { LlmAdapter } from "./llm-adapter.interface";
|
|
4
3
|
import type {
|
|
@@ -10,13 +9,12 @@ import type {
|
|
|
10
9
|
} from "../interfaces";
|
|
11
10
|
import { shouldLog } from "../../verbose";
|
|
12
11
|
|
|
13
|
-
@Injectable()
|
|
14
12
|
export class OpenAIAdapter implements LlmAdapter {
|
|
15
13
|
readonly name = "openai";
|
|
16
14
|
|
|
17
15
|
private client: OpenAI | null = null;
|
|
18
16
|
|
|
19
|
-
constructor(
|
|
17
|
+
constructor(private readonly config: LlmProxyConfig) {}
|
|
20
18
|
|
|
21
19
|
isConfigured(): boolean {
|
|
22
20
|
return !!this.config.openai;
|
|
@@ -2,6 +2,7 @@ export interface ClaudeAdapterConfig {
|
|
|
2
2
|
model?: string;
|
|
3
3
|
baseUrl?: string;
|
|
4
4
|
authToken?: string;
|
|
5
|
+
hasCompletedOnboarding?: boolean;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
export interface OpenAIAdapterConfig {
|
|
@@ -22,11 +23,18 @@ export interface OpenCodeAdapterConfig {
|
|
|
22
23
|
|
|
23
24
|
export type LLMMode = "claude-code" | "openai" | "gemini" | "open-code";
|
|
24
25
|
|
|
26
|
+
export interface GeminiAdapterConfig {
|
|
27
|
+
model?: string;
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
apiKey?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
25
32
|
export interface LlmProxyConfig {
|
|
26
33
|
defaultAdapter?: LLMMode;
|
|
27
34
|
claudeCode?: ClaudeAdapterConfig;
|
|
28
35
|
openai?: OpenAIAdapterConfig;
|
|
29
36
|
openCode?: OpenCodeAdapterConfig;
|
|
37
|
+
gemini?: GeminiAdapterConfig;
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
export const LLM_PROXY_CONFIG = Symbol("LLM_PROXY_CONFIG");
|