@downcity/city 0.2.17
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 +182 -0
- package/bin/core/auth/authenticator.d.ts +79 -0
- package/bin/core/auth/authenticator.d.ts.map +1 -0
- package/bin/core/auth/authenticator.js +125 -0
- package/bin/core/auth/authenticator.js.map +1 -0
- package/bin/core/auth/token-signer.d.ts +27 -0
- package/bin/core/auth/token-signer.d.ts.map +1 -0
- package/bin/core/auth/token-signer.js +116 -0
- package/bin/core/auth/token-signer.js.map +1 -0
- package/bin/core/auth/types.d.ts +94 -0
- package/bin/core/auth/types.d.ts.map +1 -0
- package/bin/core/auth/types.js +7 -0
- package/bin/core/auth/types.js.map +1 -0
- package/bin/core/base/base-env-catalog.d.ts +13 -0
- package/bin/core/base/base-env-catalog.d.ts.map +1 -0
- package/bin/core/base/base-env-catalog.js +85 -0
- package/bin/core/base/base-env-catalog.js.map +1 -0
- package/bin/core/base/base-init.d.ts +48 -0
- package/bin/core/base/base-init.d.ts.map +1 -0
- package/bin/core/base/base-init.js +105 -0
- package/bin/core/base/base-init.js.map +1 -0
- package/bin/core/base/base-instruction.d.ts +11 -0
- package/bin/core/base/base-instruction.d.ts.map +1 -0
- package/bin/core/base/base-instruction.js +37 -0
- package/bin/core/base/base-instruction.js.map +1 -0
- package/bin/core/base/base-router.d.ts +41 -0
- package/bin/core/base/base-router.d.ts.map +1 -0
- package/bin/core/base/base-router.js +222 -0
- package/bin/core/base/base-router.js.map +1 -0
- package/bin/core/base/base-runtime.d.ts +13 -0
- package/bin/core/base/base-runtime.d.ts.map +1 -0
- package/bin/core/base/base-runtime.js +116 -0
- package/bin/core/base/base-runtime.js.map +1 -0
- package/bin/core/base/base.d.ts +82 -0
- package/bin/core/base/base.d.ts.map +1 -0
- package/bin/core/base/base.js +156 -0
- package/bin/core/base/base.js.map +1 -0
- package/bin/core/runtime.d.ts +120 -0
- package/bin/core/runtime.d.ts.map +1 -0
- package/bin/core/runtime.js +13 -0
- package/bin/core/runtime.js.map +1 -0
- package/bin/core/types.d.ts +60 -0
- package/bin/core/types.d.ts.map +1 -0
- package/bin/core/types.js +7 -0
- package/bin/core/types.js.map +1 -0
- package/bin/index.d.ts +33 -0
- package/bin/index.d.ts.map +1 -0
- package/bin/index.js +37 -0
- package/bin/index.js.map +1 -0
- package/bin/service/action.d.ts +44 -0
- package/bin/service/action.d.ts.map +1 -0
- package/bin/service/action.js +48 -0
- package/bin/service/action.js.map +1 -0
- package/bin/service/ai/ai-service.d.ts +56 -0
- package/bin/service/ai/ai-service.d.ts.map +1 -0
- package/bin/service/ai/ai-service.js +262 -0
- package/bin/service/ai/ai-service.js.map +1 -0
- package/bin/service/ai/openai-compatible-provider.d.ts +54 -0
- package/bin/service/ai/openai-compatible-provider.d.ts.map +1 -0
- package/bin/service/ai/openai-compatible-provider.js +175 -0
- package/bin/service/ai/openai-compatible-provider.js.map +1 -0
- package/bin/service/ai/provider.d.ts +43 -0
- package/bin/service/ai/provider.d.ts.map +1 -0
- package/bin/service/ai/provider.js +50 -0
- package/bin/service/ai/provider.js.map +1 -0
- package/bin/service/ai/types.d.ts +94 -0
- package/bin/service/ai/types.d.ts.map +1 -0
- package/bin/service/ai/types.js +7 -0
- package/bin/service/ai/types.js.map +1 -0
- package/bin/service/env/env-service.d.ts +12 -0
- package/bin/service/env/env-service.d.ts.map +1 -0
- package/bin/service/env/env-service.js +39 -0
- package/bin/service/env/env-service.js.map +1 -0
- package/bin/service/env/env-store.d.ts +15 -0
- package/bin/service/env/env-store.d.ts.map +1 -0
- package/bin/service/env/env-store.js +35 -0
- package/bin/service/env/env-store.js.map +1 -0
- package/bin/service/env/schema.d.ts +171 -0
- package/bin/service/env/schema.d.ts.map +1 -0
- package/bin/service/env/schema.js +52 -0
- package/bin/service/env/schema.js.map +1 -0
- package/bin/service/env/types.d.ts +79 -0
- package/bin/service/env/types.d.ts.map +1 -0
- package/bin/service/env/types.js +8 -0
- package/bin/service/env/types.js.map +1 -0
- package/bin/service/hook.d.ts +23 -0
- package/bin/service/hook.d.ts.map +1 -0
- package/bin/service/hook.js +49 -0
- package/bin/service/hook.js.map +1 -0
- package/bin/service/installable-service.d.ts +75 -0
- package/bin/service/installable-service.d.ts.map +1 -0
- package/bin/service/installable-service.js +89 -0
- package/bin/service/installable-service.js.map +1 -0
- package/bin/service/instruction.d.ts +106 -0
- package/bin/service/instruction.d.ts.map +1 -0
- package/bin/service/instruction.js +70 -0
- package/bin/service/instruction.js.map +1 -0
- package/bin/service/service.d.ts +140 -0
- package/bin/service/service.d.ts.map +1 -0
- package/bin/service/service.js +94 -0
- package/bin/service/service.js.map +1 -0
- package/bin/service/studios/schema.d.ts +207 -0
- package/bin/service/studios/schema.d.ts.map +1 -0
- package/bin/service/studios/schema.js +60 -0
- package/bin/service/studios/schema.js.map +1 -0
- package/bin/service/studios/studio-store.d.ts +17 -0
- package/bin/service/studios/studio-store.d.ts.map +1 -0
- package/bin/service/studios/studio-store.js +49 -0
- package/bin/service/studios/studio-store.js.map +1 -0
- package/bin/service/studios/studios-service.d.ts +15 -0
- package/bin/service/studios/studios-service.d.ts.map +1 -0
- package/bin/service/studios/studios-service.js +51 -0
- package/bin/service/studios/studios-service.js.map +1 -0
- package/bin/service/studios/types.d.ts +51 -0
- package/bin/service/studios/types.d.ts.map +1 -0
- package/bin/service/studios/types.js +7 -0
- package/bin/service/studios/types.js.map +1 -0
- package/bin/service/types.d.ts +11 -0
- package/bin/service/types.d.ts.map +1 -0
- package/bin/service/types.js +5 -0
- package/bin/service/types.js.map +1 -0
- package/bin/store/db.d.ts +61 -0
- package/bin/store/db.d.ts.map +1 -0
- package/bin/store/db.js +29 -0
- package/bin/store/db.js.map +1 -0
- package/bin/store/table-api.d.ts +42 -0
- package/bin/store/table-api.d.ts.map +1 -0
- package/bin/store/table-api.js +100 -0
- package/bin/store/table-api.js.map +1 -0
- package/bin/store/types.d.ts +14 -0
- package/bin/store/types.d.ts.map +1 -0
- package/bin/store/types.js +7 -0
- package/bin/store/types.js.map +1 -0
- package/bin/utils/helpers.d.ts +101 -0
- package/bin/utils/helpers.d.ts.map +1 -0
- package/bin/utils/helpers.js +192 -0
- package/bin/utils/helpers.js.map +1 -0
- package/bin/utils/validation.d.ts +18 -0
- package/bin/utils/validation.d.ts.map +1 -0
- package/bin/utils/validation.js +28 -0
- package/bin/utils/validation.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI-compatible Provider 构造工具。
|
|
3
|
+
*
|
|
4
|
+
* 负责把 OpenAI 兼容上游包装成 Downcity 的 SDK 通路:
|
|
5
|
+
* - text → 返回 AI SDK `UIMessage`
|
|
6
|
+
* - stream → 返回 AI SDK `UIMessageStreamResponse`
|
|
7
|
+
*
|
|
8
|
+
* 关键说明(中文)
|
|
9
|
+
* - `/chat/completions` 仍由 AIService 的自动透传处理
|
|
10
|
+
* - 这里专门补齐 UserClient.ai.text() / stream() 所需的 server 侧 action
|
|
11
|
+
* - 不在请求热路径里做动态导入,减少首请求和冷启动额外开销
|
|
12
|
+
*/
|
|
13
|
+
import { convertToModelMessages, generateText, jsonSchema, streamText, tool } from "ai";
|
|
14
|
+
import { Provider } from "./provider.js";
|
|
15
|
+
/**
|
|
16
|
+
* 创建 OpenAI-compatible Provider。
|
|
17
|
+
*/
|
|
18
|
+
export function createOpenAICompatibleProvider(options, createClient) {
|
|
19
|
+
return new Provider(options.id, {
|
|
20
|
+
env: { [options.envKey]: `${options.id} API Key` },
|
|
21
|
+
baseURL: options.baseURL,
|
|
22
|
+
envKey: options.envKey,
|
|
23
|
+
passthroughModel: options.defaultModelId,
|
|
24
|
+
text: createTextAction(options, createClient),
|
|
25
|
+
stream: createStreamAction(options, createClient),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 读取必填 API Key。
|
|
30
|
+
*/
|
|
31
|
+
function readApiKey(ctx, key) {
|
|
32
|
+
const value = ctx.env(key);
|
|
33
|
+
if (!value)
|
|
34
|
+
throw new Error(`${key} is required`);
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 从 input 中提取 prompt 文本。
|
|
39
|
+
*/
|
|
40
|
+
function extractPrompt(input) {
|
|
41
|
+
if (typeof input.prompt === "string")
|
|
42
|
+
return input.prompt;
|
|
43
|
+
const messages = input.messages;
|
|
44
|
+
return messages
|
|
45
|
+
?.find((message) => message.role === "user")
|
|
46
|
+
?.parts?.find((part) => part.type === "text")
|
|
47
|
+
?.text ?? "";
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* OpenAI function tools → ai-sdk ToolSet。
|
|
51
|
+
*/
|
|
52
|
+
function buildToolSet(items) {
|
|
53
|
+
if (!items?.length)
|
|
54
|
+
return undefined;
|
|
55
|
+
return Object.fromEntries(items
|
|
56
|
+
.filter((item) => item.type === "function" && typeof item.function?.name === "string")
|
|
57
|
+
.map((item) => [
|
|
58
|
+
item.function.name,
|
|
59
|
+
tool({
|
|
60
|
+
description: item.function.description ?? "",
|
|
61
|
+
inputSchema: jsonSchema(item.function.parameters ?? {}),
|
|
62
|
+
}),
|
|
63
|
+
]));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 将输入解析成 prompt 或 tools+messages,供 text / stream 共用。
|
|
67
|
+
*/
|
|
68
|
+
async function resolveActionInput(input) {
|
|
69
|
+
const tools = buildToolSet(input.tools);
|
|
70
|
+
if (!tools) {
|
|
71
|
+
return { prompt: extractPrompt(input) };
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
tools,
|
|
75
|
+
messages: await convertToModelMessages(input.messages ?? [], { tools }),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 创建当前请求的 chat model。
|
|
80
|
+
*
|
|
81
|
+
* 关键说明(中文)
|
|
82
|
+
* - client 工厂本身在模块加载时就已静态绑定
|
|
83
|
+
* - 这里只按当前 env 读取 API Key,避免 key 轮换后继续复用旧值
|
|
84
|
+
*/
|
|
85
|
+
function createChatModel(ctx, options, createClient) {
|
|
86
|
+
return createClient({
|
|
87
|
+
apiKey: readApiKey(ctx, options.envKey),
|
|
88
|
+
baseURL: options.baseURL,
|
|
89
|
+
name: options.id,
|
|
90
|
+
}).chat(options.defaultModelId);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* generateText 结果 → UIMessage。
|
|
94
|
+
*/
|
|
95
|
+
function buildMessage(text, ctx, result) {
|
|
96
|
+
const parts = [{ type: "text", text }];
|
|
97
|
+
if (result.toolCalls) {
|
|
98
|
+
for (const toolCall of result.toolCalls) {
|
|
99
|
+
const part = {
|
|
100
|
+
type: "dynamic-tool",
|
|
101
|
+
toolCallId: toolCall.toolCallId,
|
|
102
|
+
toolName: toolCall.toolName,
|
|
103
|
+
state: "input-available",
|
|
104
|
+
input: toolCall.input,
|
|
105
|
+
};
|
|
106
|
+
parts.push(part);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
id: `msg_${crypto.randomUUID()}`,
|
|
111
|
+
role: "assistant",
|
|
112
|
+
parts,
|
|
113
|
+
metadata: {
|
|
114
|
+
model: ctx.variant?.id,
|
|
115
|
+
studio_id: ctx.studio?.studio_id,
|
|
116
|
+
user_id: ctx.user?.user_id,
|
|
117
|
+
finishReason: result.finishReason,
|
|
118
|
+
usage: result.usage,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 构造 text action。
|
|
124
|
+
*/
|
|
125
|
+
function createTextAction(options, createClient) {
|
|
126
|
+
return async (ctx) => {
|
|
127
|
+
const input = ctx.input;
|
|
128
|
+
const resolvedInput = await resolveActionInput(input);
|
|
129
|
+
const model = createChatModel(ctx, options, createClient);
|
|
130
|
+
if ("tools" in resolvedInput) {
|
|
131
|
+
const result = await generateText({
|
|
132
|
+
model,
|
|
133
|
+
messages: resolvedInput.messages,
|
|
134
|
+
tools: resolvedInput.tools,
|
|
135
|
+
});
|
|
136
|
+
return buildMessage(result.text, ctx, {
|
|
137
|
+
finishReason: result.finishReason,
|
|
138
|
+
usage: result.usage,
|
|
139
|
+
toolCalls: result.toolCalls,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
const result = await generateText({
|
|
143
|
+
model,
|
|
144
|
+
prompt: resolvedInput.prompt,
|
|
145
|
+
temperature: 1,
|
|
146
|
+
});
|
|
147
|
+
return buildMessage(result.text, ctx, {
|
|
148
|
+
finishReason: result.finishReason,
|
|
149
|
+
usage: result.usage,
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 构造 stream action。
|
|
155
|
+
*/
|
|
156
|
+
function createStreamAction(options, createClient) {
|
|
157
|
+
return async (ctx) => {
|
|
158
|
+
const input = ctx.input;
|
|
159
|
+
const resolvedInput = await resolveActionInput(input);
|
|
160
|
+
const model = createChatModel(ctx, options, createClient);
|
|
161
|
+
if ("tools" in resolvedInput) {
|
|
162
|
+
return streamText({
|
|
163
|
+
model,
|
|
164
|
+
messages: resolvedInput.messages,
|
|
165
|
+
tools: resolvedInput.tools,
|
|
166
|
+
}).toUIMessageStreamResponse();
|
|
167
|
+
}
|
|
168
|
+
return streamText({
|
|
169
|
+
model,
|
|
170
|
+
prompt: resolvedInput.prompt,
|
|
171
|
+
temperature: 1,
|
|
172
|
+
}).toUIMessageStreamResponse();
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=openai-compatible-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible-provider.js","sourceRoot":"","sources":["../../../src/service/ai/openai-compatible-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider 模块。
|
|
3
|
+
*
|
|
4
|
+
* Provider 封装第三方 AI 提供商的 action 实现、环境变量声明和连接信息。
|
|
5
|
+
* 通过 model() 方法生成模型配置,可直接传给 AIService.use() 完成注册。
|
|
6
|
+
*
|
|
7
|
+
* 两条独立通路:
|
|
8
|
+
* - SDK 通路:text / stream — 给 UserClient 用
|
|
9
|
+
* - OpenAI 兼容通路:openai — 给 /chat/completions 端点用
|
|
10
|
+
* - 未提供 openai action → AIService 自动透传(需 baseURL + envKey)
|
|
11
|
+
* - 提供了 openai action → 按自定义逻辑处理
|
|
12
|
+
*/
|
|
13
|
+
import type { ActionFn } from "../action.js";
|
|
14
|
+
import type { ModelConfig } from "./types.js";
|
|
15
|
+
export interface ProviderOptions {
|
|
16
|
+
env?: Record<string, string>;
|
|
17
|
+
baseURL?: string;
|
|
18
|
+
envKey?: string;
|
|
19
|
+
passthroughModel?: string;
|
|
20
|
+
text: ActionFn;
|
|
21
|
+
stream: ActionFn;
|
|
22
|
+
image?: ActionFn;
|
|
23
|
+
video?: ActionFn;
|
|
24
|
+
openai?: ActionFn;
|
|
25
|
+
}
|
|
26
|
+
export declare class Provider {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly env?: Record<string, string>;
|
|
29
|
+
readonly baseURL?: string;
|
|
30
|
+
readonly envKey?: string;
|
|
31
|
+
readonly passthroughModel?: string;
|
|
32
|
+
private readonly actions;
|
|
33
|
+
constructor(id: string, opts: ProviderOptions);
|
|
34
|
+
model(spec: {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
tags?: string[];
|
|
39
|
+
meta?: Record<string, unknown>;
|
|
40
|
+
default?: boolean | string[];
|
|
41
|
+
}): ModelConfig;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/service/ai/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,qBAAa,QAAQ;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe;IAe7C,KAAK,CAAC,IAAI,EAAE;QACV,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;KAC9B,GAAG,WAAW;CAehB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider 模块。
|
|
3
|
+
*
|
|
4
|
+
* Provider 封装第三方 AI 提供商的 action 实现、环境变量声明和连接信息。
|
|
5
|
+
* 通过 model() 方法生成模型配置,可直接传给 AIService.use() 完成注册。
|
|
6
|
+
*
|
|
7
|
+
* 两条独立通路:
|
|
8
|
+
* - SDK 通路:text / stream — 给 UserClient 用
|
|
9
|
+
* - OpenAI 兼容通路:openai — 给 /chat/completions 端点用
|
|
10
|
+
* - 未提供 openai action → AIService 自动透传(需 baseURL + envKey)
|
|
11
|
+
* - 提供了 openai action → 按自定义逻辑处理
|
|
12
|
+
*/
|
|
13
|
+
export class Provider {
|
|
14
|
+
id;
|
|
15
|
+
env;
|
|
16
|
+
baseURL;
|
|
17
|
+
envKey;
|
|
18
|
+
passthroughModel;
|
|
19
|
+
actions;
|
|
20
|
+
constructor(id, opts) {
|
|
21
|
+
this.id = id;
|
|
22
|
+
this.env = opts.env;
|
|
23
|
+
this.baseURL = opts.baseURL;
|
|
24
|
+
this.envKey = opts.envKey;
|
|
25
|
+
this.passthroughModel = opts.passthroughModel;
|
|
26
|
+
this.actions = {
|
|
27
|
+
text: opts.text,
|
|
28
|
+
stream: opts.stream,
|
|
29
|
+
image: opts.image,
|
|
30
|
+
video: opts.video,
|
|
31
|
+
openai: opts.openai,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
model(spec) {
|
|
35
|
+
return {
|
|
36
|
+
id: spec.id,
|
|
37
|
+
name: spec.name,
|
|
38
|
+
description: spec.description,
|
|
39
|
+
tags: spec.tags,
|
|
40
|
+
meta: spec.meta,
|
|
41
|
+
default: spec.default,
|
|
42
|
+
env: this.env,
|
|
43
|
+
baseURL: this.baseURL,
|
|
44
|
+
envKey: this.envKey,
|
|
45
|
+
passthroughModel: this.passthroughModel,
|
|
46
|
+
actions: this.actions,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/service/ai/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiBH,MAAM,OAAO,QAAQ;IACV,EAAE,CAAS;IACX,GAAG,CAA0B;IAC7B,OAAO,CAAU;IACjB,MAAM,CAAU;IAChB,gBAAgB,CAAU;IAClB,OAAO,CAAe;IAEvC,YAAY,EAAU,EAAE,IAAqB;QAC3C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC9C,IAAI,CAAC,OAAO,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAOL;QACC,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Service 类型模块。
|
|
3
|
+
*
|
|
4
|
+
* 包含模型配置、action 映射、运行时模型和执行上下文类型。
|
|
5
|
+
*/
|
|
6
|
+
import type { ActionFn } from "../action.js";
|
|
7
|
+
/**
|
|
8
|
+
* 模型 action 映射,key 为通路名称。
|
|
9
|
+
*
|
|
10
|
+
* 两条独立通路:
|
|
11
|
+
* - SDK 通路:text / stream / image / video / tts / asr — 给 UserClient 用
|
|
12
|
+
* - OpenAI 兼容通路:openai — 给 /chat/completions 端点用
|
|
13
|
+
*
|
|
14
|
+
* 每个 action 接收 Context,返回对应通路的结果。
|
|
15
|
+
* Provider 在构造时提供这些 action,通过 model() 方法绑定到模型配置。
|
|
16
|
+
*/
|
|
17
|
+
export interface ModelActions {
|
|
18
|
+
/** 文本生成 action */
|
|
19
|
+
text?: ActionFn;
|
|
20
|
+
/** 流式生成 action */
|
|
21
|
+
stream?: ActionFn;
|
|
22
|
+
/** 图片生成 action */
|
|
23
|
+
image?: ActionFn;
|
|
24
|
+
/** 视频生成 action */
|
|
25
|
+
video?: ActionFn;
|
|
26
|
+
/** 语音合成 action */
|
|
27
|
+
tts?: ActionFn;
|
|
28
|
+
/** 语音识别 action */
|
|
29
|
+
asr?: ActionFn;
|
|
30
|
+
/** OpenAI 兼容 /chat/completions action。未提供时 AIService 自动透传 */
|
|
31
|
+
openai?: ActionFn;
|
|
32
|
+
/** 扩展 modality action */
|
|
33
|
+
[modality: string]: ActionFn | undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 模型配置(Provider.model() 的返回值)。
|
|
37
|
+
*/
|
|
38
|
+
export interface ModelConfig {
|
|
39
|
+
/** 模型唯一 ID */
|
|
40
|
+
id: string;
|
|
41
|
+
/** 模型展示名称 */
|
|
42
|
+
name: string;
|
|
43
|
+
/** 模型描述 */
|
|
44
|
+
description?: string;
|
|
45
|
+
/** 模型标签 */
|
|
46
|
+
tags?: string[];
|
|
47
|
+
/** 模型元数据 */
|
|
48
|
+
meta?: Record<string, unknown>;
|
|
49
|
+
/** 是否为默认模型 */
|
|
50
|
+
default?: boolean | string[];
|
|
51
|
+
/** 模型所需环境变量 */
|
|
52
|
+
env?: Record<string, string>;
|
|
53
|
+
/** Provider 的 baseURL(用于自动透传) */
|
|
54
|
+
baseURL?: string;
|
|
55
|
+
/** Provider 的环境变量 key */
|
|
56
|
+
envKey?: string;
|
|
57
|
+
/** 上游 API 实际模型 ID(自动透传时替换 body.model) */
|
|
58
|
+
passthroughModel?: string;
|
|
59
|
+
/** 各通路 action 绑定 */
|
|
60
|
+
actions: ModelActions;
|
|
61
|
+
}
|
|
62
|
+
export interface PublicModel {
|
|
63
|
+
/** 模型 ID */
|
|
64
|
+
id: string;
|
|
65
|
+
/** 模型展示名称 */
|
|
66
|
+
name: string;
|
|
67
|
+
/** 模型描述 */
|
|
68
|
+
description: string;
|
|
69
|
+
/** 模型支持的 modality 列表 */
|
|
70
|
+
modalities: string[];
|
|
71
|
+
/** 模型标签 */
|
|
72
|
+
tags: string[];
|
|
73
|
+
/** 模型元数据 */
|
|
74
|
+
meta: Record<string, unknown>;
|
|
75
|
+
/** 模型依赖的环境变量需求(通常仅在 admin 身份下返回) */
|
|
76
|
+
env_requirements?: AIModelEnvRequirement[];
|
|
77
|
+
/** 模型默认负责的 modality 列表(通常仅在 admin 身份下返回) */
|
|
78
|
+
default_modes?: string[];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* AI 模型环境变量需求。
|
|
82
|
+
*
|
|
83
|
+
* 用于 admin 视角展示某个模型依赖哪些运行时 key,
|
|
84
|
+
* 以及这些 key 当前是否已经配置完成。
|
|
85
|
+
*/
|
|
86
|
+
export interface AIModelEnvRequirement {
|
|
87
|
+
/** 环境变量 key,例如 `DEEPSEEK_API_KEY` */
|
|
88
|
+
key: string;
|
|
89
|
+
/** 给管理员展示的说明文本 */
|
|
90
|
+
description: string;
|
|
91
|
+
/** 当前是否必须提供该 key 才能调用模型 */
|
|
92
|
+
required: boolean;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/service/ai/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAM7C;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,kBAAkB;IAClB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,kBAAkB;IAClB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,kBAAkB;IAClB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,kBAAkB;IAClB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,kBAAkB;IAClB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,kBAAkB;IAClB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,6DAA6D;IAC7D,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,yBAAyB;IACzB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,cAAc;IACd,EAAE,EAAE,MAAM,CAAC;IACX,aAAa;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc;IACd,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;IAC7B,eAAe;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB;IACpB,OAAO,EAAE,YAAY,CAAC;CACvB;AAMD,MAAM,WAAW,WAAW;IAC1B,YAAY;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,aAAa;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW;IACX,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,oCAAoC;IACpC,gBAAgB,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAC3C,4CAA4C;IAC5C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,kBAAkB;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,QAAQ,EAAE,OAAO,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/service/ai/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* env 内置服务。
|
|
3
|
+
*
|
|
4
|
+
* 关键说明(中文)
|
|
5
|
+
* - City 默认注册该 service。
|
|
6
|
+
* - EnvProvider 由 City 初始化并注入,不需要产品手动传入。
|
|
7
|
+
*/
|
|
8
|
+
import { Service } from "../service.js";
|
|
9
|
+
export declare class EnvService extends Service {
|
|
10
|
+
constructor();
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=env-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-service.d.ts","sourceRoot":"","sources":["../../../src/service/env/env-service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,qBAAa,UAAW,SAAQ,OAAO;;CAiCtC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* env 内置服务。
|
|
3
|
+
*
|
|
4
|
+
* 关键说明(中文)
|
|
5
|
+
* - City 默认注册该 service。
|
|
6
|
+
* - EnvProvider 由 City 初始化并注入,不需要产品手动传入。
|
|
7
|
+
*/
|
|
8
|
+
import { Service } from "../service.js";
|
|
9
|
+
export class EnvService extends Service {
|
|
10
|
+
constructor() {
|
|
11
|
+
super({ id: "env", name: "Env" });
|
|
12
|
+
this.instruction = [
|
|
13
|
+
"管理 City 运行时环境变量。",
|
|
14
|
+
"适用于导入、列出、更新和删除 City 内部使用的 env 配置。",
|
|
15
|
+
"不要把真实密钥暴露给产品前端;应只在可信管理端调用这些接口。",
|
|
16
|
+
].join("\n");
|
|
17
|
+
this.action("list", async (ctx) => {
|
|
18
|
+
const list = await this._env.list();
|
|
19
|
+
const items = Array.isArray(list) ? list : [];
|
|
20
|
+
return { items };
|
|
21
|
+
}, { method: "GET", auth: ["admin"] });
|
|
22
|
+
this.action("upsert", async (ctx) => {
|
|
23
|
+
const entry = await this._env.upsert({
|
|
24
|
+
key: String(ctx.input.key ?? ""),
|
|
25
|
+
value: String(ctx.input.value ?? ""),
|
|
26
|
+
});
|
|
27
|
+
return { success: true, key: entry.key };
|
|
28
|
+
}, { auth: ["admin"] });
|
|
29
|
+
this.action("remove", async (ctx) => {
|
|
30
|
+
await this._env.remove(String(ctx.input.key ?? ""));
|
|
31
|
+
return { success: true, key: String(ctx.input.key ?? "") };
|
|
32
|
+
}, { auth: ["admin"] });
|
|
33
|
+
this.action("import", async (ctx) => {
|
|
34
|
+
const entries = await this._env.import(ctx.input.raw);
|
|
35
|
+
return { success: true, count: entries.length, keys: entries.map((e) => e.key) };
|
|
36
|
+
}, { auth: ["admin"] });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=env-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-service.js","sourceRoot":"","sources":["../../../src/service/env/env-service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,OAAO,UAAW,SAAQ,OAAO;IACrC;QACE,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG;YACjB,kBAAkB;YAClB,mCAAmC;YACnC,gCAAgC;SACjC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAChC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAK,CAAC,IAAI,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,OAAO,EAAE,KAAK,EAAE,CAAC;QACnB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEvC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAClC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAK,CAAC,MAAM,CAAC;gBACpC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;gBAChC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;aACrC,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;QAC3C,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAExB,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAClC,MAAM,IAAI,CAAC,IAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;YACrD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC;QAC7D,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAExB,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAClC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACvD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;QACnF,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Env 数据存储。
|
|
3
|
+
*
|
|
4
|
+
* 基于 CityTableApi,不直接依赖 Drizzle。
|
|
5
|
+
*/
|
|
6
|
+
import type { CityTableApi } from "../../store/table-api.js";
|
|
7
|
+
import type { EnvEntry, EnvUpsertInput } from "./types.js";
|
|
8
|
+
export declare class EnvStore {
|
|
9
|
+
private table;
|
|
10
|
+
constructor(table: CityTableApi<EnvEntry>);
|
|
11
|
+
list(): Promise<EnvEntry[]>;
|
|
12
|
+
upsert(input: EnvUpsertInput): Promise<EnvEntry>;
|
|
13
|
+
remove(key: string): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=env-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-store.d.ts","sourceRoot":"","sources":["../../../src/service/env/env-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3D,qBAAa,QAAQ;IACP,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC;IAE3C,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAI3B,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC;IAkBhD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGzC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Env 数据存储。
|
|
3
|
+
*
|
|
4
|
+
* 基于 CityTableApi,不直接依赖 Drizzle。
|
|
5
|
+
*/
|
|
6
|
+
import { normalizeEnvKey } from "../../utils/helpers.js";
|
|
7
|
+
export class EnvStore {
|
|
8
|
+
table;
|
|
9
|
+
constructor(table) {
|
|
10
|
+
this.table = table;
|
|
11
|
+
}
|
|
12
|
+
async list() {
|
|
13
|
+
return this.table.select();
|
|
14
|
+
}
|
|
15
|
+
async upsert(input) {
|
|
16
|
+
const key = normalizeEnvKey(input.key);
|
|
17
|
+
const value = String(input.value ?? "");
|
|
18
|
+
const rows = await this.table.select({ key });
|
|
19
|
+
if (rows.length > 0) {
|
|
20
|
+
await this.table.update({
|
|
21
|
+
where: { key },
|
|
22
|
+
values: { value, updated_at: new Date().toISOString() },
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const now = new Date().toISOString();
|
|
27
|
+
await this.table.insert({ key, value, source: "database", created_at: now, updated_at: now });
|
|
28
|
+
}
|
|
29
|
+
return { key, value, source: "database" };
|
|
30
|
+
}
|
|
31
|
+
async remove(key) {
|
|
32
|
+
await this.table.delete({ key: normalizeEnvKey(key) });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=env-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-store.js","sourceRoot":"","sources":["../../../src/service/env/env-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIzD,MAAM,OAAO,QAAQ;IACC;IAApB,YAAoB,KAA6B;QAA7B,UAAK,GAAL,KAAK,CAAwB;IAAG,CAAC;IAErD,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAqB;QAChC,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,EAAuB,CAAC,CAAC;QAEnE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;gBACtB,KAAK,EAAE,EAAE,GAAG,EAAuB;gBACnC,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAuB;aAC7E,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAc,CAAC,CAAC;QAC5G,CAAC;QAED,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,EAAuB,CAAC,CAAC;IAC9E,CAAC;CACF"}
|