@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.
Files changed (142) hide show
  1. package/README.md +182 -0
  2. package/bin/core/auth/authenticator.d.ts +79 -0
  3. package/bin/core/auth/authenticator.d.ts.map +1 -0
  4. package/bin/core/auth/authenticator.js +125 -0
  5. package/bin/core/auth/authenticator.js.map +1 -0
  6. package/bin/core/auth/token-signer.d.ts +27 -0
  7. package/bin/core/auth/token-signer.d.ts.map +1 -0
  8. package/bin/core/auth/token-signer.js +116 -0
  9. package/bin/core/auth/token-signer.js.map +1 -0
  10. package/bin/core/auth/types.d.ts +94 -0
  11. package/bin/core/auth/types.d.ts.map +1 -0
  12. package/bin/core/auth/types.js +7 -0
  13. package/bin/core/auth/types.js.map +1 -0
  14. package/bin/core/base/base-env-catalog.d.ts +13 -0
  15. package/bin/core/base/base-env-catalog.d.ts.map +1 -0
  16. package/bin/core/base/base-env-catalog.js +85 -0
  17. package/bin/core/base/base-env-catalog.js.map +1 -0
  18. package/bin/core/base/base-init.d.ts +48 -0
  19. package/bin/core/base/base-init.d.ts.map +1 -0
  20. package/bin/core/base/base-init.js +105 -0
  21. package/bin/core/base/base-init.js.map +1 -0
  22. package/bin/core/base/base-instruction.d.ts +11 -0
  23. package/bin/core/base/base-instruction.d.ts.map +1 -0
  24. package/bin/core/base/base-instruction.js +37 -0
  25. package/bin/core/base/base-instruction.js.map +1 -0
  26. package/bin/core/base/base-router.d.ts +41 -0
  27. package/bin/core/base/base-router.d.ts.map +1 -0
  28. package/bin/core/base/base-router.js +222 -0
  29. package/bin/core/base/base-router.js.map +1 -0
  30. package/bin/core/base/base-runtime.d.ts +13 -0
  31. package/bin/core/base/base-runtime.d.ts.map +1 -0
  32. package/bin/core/base/base-runtime.js +116 -0
  33. package/bin/core/base/base-runtime.js.map +1 -0
  34. package/bin/core/base/base.d.ts +82 -0
  35. package/bin/core/base/base.d.ts.map +1 -0
  36. package/bin/core/base/base.js +156 -0
  37. package/bin/core/base/base.js.map +1 -0
  38. package/bin/core/runtime.d.ts +120 -0
  39. package/bin/core/runtime.d.ts.map +1 -0
  40. package/bin/core/runtime.js +13 -0
  41. package/bin/core/runtime.js.map +1 -0
  42. package/bin/core/types.d.ts +60 -0
  43. package/bin/core/types.d.ts.map +1 -0
  44. package/bin/core/types.js +7 -0
  45. package/bin/core/types.js.map +1 -0
  46. package/bin/index.d.ts +33 -0
  47. package/bin/index.d.ts.map +1 -0
  48. package/bin/index.js +37 -0
  49. package/bin/index.js.map +1 -0
  50. package/bin/service/action.d.ts +44 -0
  51. package/bin/service/action.d.ts.map +1 -0
  52. package/bin/service/action.js +48 -0
  53. package/bin/service/action.js.map +1 -0
  54. package/bin/service/ai/ai-service.d.ts +56 -0
  55. package/bin/service/ai/ai-service.d.ts.map +1 -0
  56. package/bin/service/ai/ai-service.js +262 -0
  57. package/bin/service/ai/ai-service.js.map +1 -0
  58. package/bin/service/ai/openai-compatible-provider.d.ts +54 -0
  59. package/bin/service/ai/openai-compatible-provider.d.ts.map +1 -0
  60. package/bin/service/ai/openai-compatible-provider.js +175 -0
  61. package/bin/service/ai/openai-compatible-provider.js.map +1 -0
  62. package/bin/service/ai/provider.d.ts +43 -0
  63. package/bin/service/ai/provider.d.ts.map +1 -0
  64. package/bin/service/ai/provider.js +50 -0
  65. package/bin/service/ai/provider.js.map +1 -0
  66. package/bin/service/ai/types.d.ts +94 -0
  67. package/bin/service/ai/types.d.ts.map +1 -0
  68. package/bin/service/ai/types.js +7 -0
  69. package/bin/service/ai/types.js.map +1 -0
  70. package/bin/service/env/env-service.d.ts +12 -0
  71. package/bin/service/env/env-service.d.ts.map +1 -0
  72. package/bin/service/env/env-service.js +39 -0
  73. package/bin/service/env/env-service.js.map +1 -0
  74. package/bin/service/env/env-store.d.ts +15 -0
  75. package/bin/service/env/env-store.d.ts.map +1 -0
  76. package/bin/service/env/env-store.js +35 -0
  77. package/bin/service/env/env-store.js.map +1 -0
  78. package/bin/service/env/schema.d.ts +171 -0
  79. package/bin/service/env/schema.d.ts.map +1 -0
  80. package/bin/service/env/schema.js +52 -0
  81. package/bin/service/env/schema.js.map +1 -0
  82. package/bin/service/env/types.d.ts +79 -0
  83. package/bin/service/env/types.d.ts.map +1 -0
  84. package/bin/service/env/types.js +8 -0
  85. package/bin/service/env/types.js.map +1 -0
  86. package/bin/service/hook.d.ts +23 -0
  87. package/bin/service/hook.d.ts.map +1 -0
  88. package/bin/service/hook.js +49 -0
  89. package/bin/service/hook.js.map +1 -0
  90. package/bin/service/installable-service.d.ts +75 -0
  91. package/bin/service/installable-service.d.ts.map +1 -0
  92. package/bin/service/installable-service.js +89 -0
  93. package/bin/service/installable-service.js.map +1 -0
  94. package/bin/service/instruction.d.ts +106 -0
  95. package/bin/service/instruction.d.ts.map +1 -0
  96. package/bin/service/instruction.js +70 -0
  97. package/bin/service/instruction.js.map +1 -0
  98. package/bin/service/service.d.ts +140 -0
  99. package/bin/service/service.d.ts.map +1 -0
  100. package/bin/service/service.js +94 -0
  101. package/bin/service/service.js.map +1 -0
  102. package/bin/service/studios/schema.d.ts +207 -0
  103. package/bin/service/studios/schema.d.ts.map +1 -0
  104. package/bin/service/studios/schema.js +60 -0
  105. package/bin/service/studios/schema.js.map +1 -0
  106. package/bin/service/studios/studio-store.d.ts +17 -0
  107. package/bin/service/studios/studio-store.d.ts.map +1 -0
  108. package/bin/service/studios/studio-store.js +49 -0
  109. package/bin/service/studios/studio-store.js.map +1 -0
  110. package/bin/service/studios/studios-service.d.ts +15 -0
  111. package/bin/service/studios/studios-service.d.ts.map +1 -0
  112. package/bin/service/studios/studios-service.js +51 -0
  113. package/bin/service/studios/studios-service.js.map +1 -0
  114. package/bin/service/studios/types.d.ts +51 -0
  115. package/bin/service/studios/types.d.ts.map +1 -0
  116. package/bin/service/studios/types.js +7 -0
  117. package/bin/service/studios/types.js.map +1 -0
  118. package/bin/service/types.d.ts +11 -0
  119. package/bin/service/types.d.ts.map +1 -0
  120. package/bin/service/types.js +5 -0
  121. package/bin/service/types.js.map +1 -0
  122. package/bin/store/db.d.ts +61 -0
  123. package/bin/store/db.d.ts.map +1 -0
  124. package/bin/store/db.js +29 -0
  125. package/bin/store/db.js.map +1 -0
  126. package/bin/store/table-api.d.ts +42 -0
  127. package/bin/store/table-api.d.ts.map +1 -0
  128. package/bin/store/table-api.js +100 -0
  129. package/bin/store/table-api.js.map +1 -0
  130. package/bin/store/types.d.ts +14 -0
  131. package/bin/store/types.d.ts.map +1 -0
  132. package/bin/store/types.js +7 -0
  133. package/bin/store/types.js.map +1 -0
  134. package/bin/utils/helpers.d.ts +101 -0
  135. package/bin/utils/helpers.d.ts.map +1 -0
  136. package/bin/utils/helpers.js +192 -0
  137. package/bin/utils/helpers.js.map +1 -0
  138. package/bin/utils/validation.d.ts +18 -0
  139. package/bin/utils/validation.d.ts.map +1 -0
  140. package/bin/utils/validation.js +28 -0
  141. package/bin/utils/validation.js.map +1 -0
  142. 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,7 @@
1
+ /**
2
+ * AI Service 类型模块。
3
+ *
4
+ * 包含模型配置、action 映射、运行时模型和执行上下文类型。
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -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"}