@downcity/city 0.2.200 → 0.2.205

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 (118) hide show
  1. package/README.md +26 -8
  2. package/bin/index.d.ts +3 -7
  3. package/bin/index.d.ts.map +1 -1
  4. package/bin/index.js +2 -2
  5. package/bin/index.js.map +1 -1
  6. package/bin/pact/invoker/ai/CityModel.d.ts +1 -1
  7. package/bin/pact/invoker/ai/CityModel.d.ts.map +1 -1
  8. package/bin/pact/invoker/ai/CityModel.js +3 -65
  9. package/bin/pact/invoker/ai/CityModel.js.map +1 -1
  10. package/bin/pact/invoker/ai/types.d.ts +1 -1
  11. package/bin/pact/invoker/ai/types.js +1 -1
  12. package/bin/pact/user/types.d.ts +11 -4
  13. package/bin/pact/user/types.d.ts.map +1 -1
  14. package/bin/service/ai/AIChannel.d.ts +57 -0
  15. package/bin/service/ai/AIChannel.d.ts.map +1 -0
  16. package/bin/service/ai/AIChannel.js +151 -0
  17. package/bin/service/ai/AIChannel.js.map +1 -0
  18. package/bin/service/ai/OpenAIChatCompletionsAdapter.d.ts +23 -0
  19. package/bin/service/ai/OpenAIChatCompletionsAdapter.d.ts.map +1 -0
  20. package/bin/service/ai/OpenAIChatCompletionsAdapter.js +503 -0
  21. package/bin/service/ai/OpenAIChatCompletionsAdapter.js.map +1 -0
  22. package/bin/service/ai/ai-service-values.d.ts +16 -19
  23. package/bin/service/ai/ai-service-values.d.ts.map +1 -1
  24. package/bin/service/ai/ai-service-values.js +9 -13
  25. package/bin/service/ai/ai-service-values.js.map +1 -1
  26. package/bin/service/ai/ai-service.d.ts +15 -14
  27. package/bin/service/ai/ai-service.d.ts.map +1 -1
  28. package/bin/service/ai/ai-service.js +97 -106
  29. package/bin/service/ai/ai-service.js.map +1 -1
  30. package/bin/service/ai/helpers.d.ts +8 -35
  31. package/bin/service/ai/helpers.d.ts.map +1 -1
  32. package/bin/service/ai/helpers.js +8 -140
  33. package/bin/service/ai/helpers.js.map +1 -1
  34. package/bin/service/ai/image-job-store.d.ts +2 -3
  35. package/bin/service/ai/image-job-store.d.ts.map +1 -1
  36. package/bin/service/ai/image-job-store.js.map +1 -1
  37. package/bin/service/ai/language-model-stream.d.ts +9 -4
  38. package/bin/service/ai/language-model-stream.d.ts.map +1 -1
  39. package/bin/service/ai/language-model-stream.js +8 -4
  40. package/bin/service/ai/language-model-stream.js.map +1 -1
  41. package/bin/service/ai/language-model-text.d.ts +15 -0
  42. package/bin/service/ai/language-model-text.d.ts.map +1 -0
  43. package/bin/service/ai/language-model-text.js +67 -0
  44. package/bin/service/ai/language-model-text.js.map +1 -0
  45. package/bin/service/ai/model-context-window.d.ts +2 -2
  46. package/bin/service/ai/model-context-window.d.ts.map +1 -1
  47. package/bin/service/ai/model-context-window.js.map +1 -1
  48. package/bin/service/ai/model-registry.d.ts +8 -7
  49. package/bin/service/ai/model-registry.d.ts.map +1 -1
  50. package/bin/service/ai/model-registry.js +1 -5
  51. package/bin/service/ai/model-registry.js.map +1 -1
  52. package/bin/service/ai/model-routing.d.ts +1 -1
  53. package/bin/service/ai/model-routing.d.ts.map +1 -1
  54. package/bin/service/ai/model-routing.js +1 -1
  55. package/bin/service/ai/model-routing.js.map +1 -1
  56. package/bin/service/ai/reasoning.d.ts +4 -4
  57. package/bin/service/ai/reasoning.d.ts.map +1 -1
  58. package/bin/service/ai/reasoning.js.map +1 -1
  59. package/bin/service/service.d.ts +8 -1
  60. package/bin/service/service.d.ts.map +1 -1
  61. package/bin/service/service.js.map +1 -1
  62. package/bin/types/AI.d.ts +289 -0
  63. package/bin/types/AI.d.ts.map +1 -0
  64. package/bin/types/AI.js +8 -0
  65. package/bin/types/AI.js.map +1 -0
  66. package/bin/types/AITransport.d.ts +251 -0
  67. package/bin/types/AITransport.d.ts.map +1 -0
  68. package/bin/types/AITransport.js +12 -0
  69. package/bin/types/AITransport.js.map +1 -0
  70. package/bin/types/Metering.d.ts +2 -2
  71. package/bin/types/Metering.d.ts.map +1 -1
  72. package/bin/utils/CityLanguageModelCodec.d.ts +1 -1
  73. package/bin/utils/CityLanguageModelCodec.d.ts.map +1 -1
  74. package/bin/utils/CityLanguageModelResult.d.ts +11 -0
  75. package/bin/utils/CityLanguageModelResult.d.ts.map +1 -0
  76. package/bin/utils/CityLanguageModelResult.js +76 -0
  77. package/bin/utils/CityLanguageModelResult.js.map +1 -0
  78. package/package.json +2 -2
  79. package/bin/service/ai/charge.d.ts +0 -76
  80. package/bin/service/ai/charge.d.ts.map +0 -1
  81. package/bin/service/ai/charge.js +0 -10
  82. package/bin/service/ai/charge.js.map +0 -1
  83. package/bin/service/ai/job-types.d.ts +0 -69
  84. package/bin/service/ai/job-types.d.ts.map +0 -1
  85. package/bin/service/ai/job-types.js +0 -9
  86. package/bin/service/ai/job-types.js.map +0 -1
  87. package/bin/service/ai/provider.d.ts +0 -143
  88. package/bin/service/ai/provider.d.ts.map +0 -1
  89. package/bin/service/ai/provider.js +0 -221
  90. package/bin/service/ai/provider.js.map +0 -1
  91. package/bin/service/ai/types.d.ts +0 -174
  92. package/bin/service/ai/types.d.ts.map +0 -1
  93. package/bin/service/ai/types.js +0 -7
  94. package/bin/service/ai/types.js.map +0 -1
  95. package/bin/types/AIImageJobClaim.d.ts +0 -14
  96. package/bin/types/AIImageJobClaim.d.ts.map +0 -1
  97. package/bin/types/AIImageJobClaim.js +0 -7
  98. package/bin/types/AIImageJobClaim.js.map +0 -1
  99. package/bin/types/AIReasoning.d.ts +0 -25
  100. package/bin/types/AIReasoning.d.ts.map +0 -1
  101. package/bin/types/AIReasoning.js +0 -7
  102. package/bin/types/AIReasoning.js.map +0 -1
  103. package/bin/types/AIRouting.d.ts +0 -37
  104. package/bin/types/AIRouting.d.ts.map +0 -1
  105. package/bin/types/AIRouting.js +0 -7
  106. package/bin/types/AIRouting.js.map +0 -1
  107. package/bin/types/CityLanguageModelRuntime.d.ts +0 -46
  108. package/bin/types/CityLanguageModelRuntime.d.ts.map +0 -1
  109. package/bin/types/CityLanguageModelRuntime.js +0 -8
  110. package/bin/types/CityLanguageModelRuntime.js.map +0 -1
  111. package/bin/types/CityLanguageModelTransport.d.ts +0 -49
  112. package/bin/types/CityLanguageModelTransport.d.ts.map +0 -1
  113. package/bin/types/CityLanguageModelTransport.js +0 -9
  114. package/bin/types/CityLanguageModelTransport.js.map +0 -1
  115. package/bin/types/CityModelRuntime.d.ts +0 -17
  116. package/bin/types/CityModelRuntime.d.ts.map +0 -1
  117. package/bin/types/CityModelRuntime.js +0 -8
  118. package/bin/types/CityModelRuntime.js.map +0 -1
@@ -0,0 +1,76 @@
1
+ /**
2
+ * LanguageModelV3 流结果聚合工具。
3
+ *
4
+ * 该模块只理解 AI SDK LanguageModelV3 的标准流事件,不了解 Federation transport
5
+ * 或具体上游协议。CityModel 非流式调用和 AIChannel 通用 text action 复用这里,
6
+ * 保证两条入口对 text、reasoning、tool、usage 和 metadata 的收口语义一致。
7
+ */
8
+ /** 将标准 LanguageModelV3 流聚合为一次非流式生成结果。 */
9
+ export async function collect_city_language_model_stream(stream, request_body) {
10
+ const reader = stream.getReader();
11
+ const content = [];
12
+ const text_blocks = new Map();
13
+ const reasoning_blocks = new Map();
14
+ let warnings = [];
15
+ let response;
16
+ let finish_reason;
17
+ let usage;
18
+ let provider_metadata;
19
+ while (true) {
20
+ const chunk = await reader.read();
21
+ if (chunk.done)
22
+ break;
23
+ const part = chunk.value;
24
+ const type = String(part.type ?? "");
25
+ if (type === "error")
26
+ throw part.error;
27
+ if (type === "stream-start") {
28
+ warnings = Array.isArray(part.warnings) ? part.warnings : [];
29
+ }
30
+ else if (type === "response-metadata") {
31
+ const { type: _type, ...metadata } = part;
32
+ response = metadata;
33
+ }
34
+ else if (type === "text-start" || type === "reasoning-start") {
35
+ const block = {
36
+ type: type === "text-start" ? "text" : "reasoning",
37
+ text: "",
38
+ ...(part.providerMetadata
39
+ ? { providerMetadata: part.providerMetadata }
40
+ : {}),
41
+ };
42
+ content.push(block);
43
+ const blocks = type === "text-start" ? text_blocks : reasoning_blocks;
44
+ blocks.set(String(part.id), block);
45
+ }
46
+ else if (type === "text-delta" || type === "reasoning-delta") {
47
+ const blocks = type === "text-delta" ? text_blocks : reasoning_blocks;
48
+ const block = blocks.get(String(part.id));
49
+ if (block) {
50
+ block.text = `${String(block.text ?? "")}${String(part.delta ?? "")}`;
51
+ }
52
+ }
53
+ else if (["file", "source", "tool-call", "tool-result", "tool-approval-request"]
54
+ .includes(type)) {
55
+ content.push(part);
56
+ }
57
+ else if (type === "finish") {
58
+ finish_reason = part.finishReason;
59
+ usage = part.usage;
60
+ provider_metadata = part.providerMetadata;
61
+ }
62
+ }
63
+ if (!finish_reason || !usage) {
64
+ throw new Error("Language model stream ended without finish usage");
65
+ }
66
+ return {
67
+ content,
68
+ finishReason: finish_reason,
69
+ usage,
70
+ warnings,
71
+ ...(provider_metadata ? { providerMetadata: provider_metadata } : {}),
72
+ ...(request_body !== undefined ? { request: { body: request_body } } : {}),
73
+ ...(response ? { response } : {}),
74
+ };
75
+ }
76
+ //# sourceMappingURL=CityLanguageModelResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CityLanguageModelResult.js","sourceRoot":"","sources":["../../src/utils/CityLanguageModelResult.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,yCAAyC;AACzC,MAAM,CAAC,KAAK,UAAU,kCAAkC,CACtD,MAAiD,EACjD,YAAsB;IAEtB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IAClC,MAAM,OAAO,GAAmC,EAAE,CAAC;IACnD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAmC,CAAC;IAC/D,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAmC,CAAC;IACpE,IAAI,QAAQ,GAAc,EAAE,CAAC;IAC7B,IAAI,QAA6C,CAAC;IAClD,IAAI,aAAsB,CAAC;IAC3B,IAAI,KAAc,CAAC;IACnB,IAAI,iBAA0B,CAAC;IAE/B,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,IAAI;YAAE,MAAM;QACtB,MAAM,IAAI,GAAG,KAAK,CAAC,KAA2C,CAAC;QAC/D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACrC,IAAI,IAAI,KAAK,OAAO;YAAE,MAAM,IAAI,CAAC,KAAK,CAAC;QACvC,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5B,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,CAAC;aAAM,IAAI,IAAI,KAAK,mBAAmB,EAAE,CAAC;YACxC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC;YAC1C,QAAQ,GAAG,QAAQ,CAAC;QACtB,CAAC;aAAM,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC/D,MAAM,KAAK,GAAG;gBACZ,IAAI,EAAE,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW;gBAClD,IAAI,EAAE,EAAE;gBACR,GAAG,CAAC,IAAI,CAAC,gBAAgB;oBACvB,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE;oBAC7C,CAAC,CAAC,EAAE,CAAC;aACR,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,MAAM,GAAG,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,gBAAgB,CAAC;YACtE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC/D,MAAM,MAAM,GAAG,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,gBAAgB,CAAC;YACtE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1C,IAAI,KAAK,EAAE,CAAC;gBACV,KAAK,CAAC,IAAI,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;YACxE,CAAC;QACH,CAAC;aAAM,IACL,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,uBAAuB,CAAC;aACpE,QAAQ,CAAC,IAAI,CAAC,EACjB,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC;YAClC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YACnB,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,IAAI,CAAC,aAAa,IAAI,CAAC,KAAK,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,OAAO;QACL,OAAO;QACP,YAAY,EAAE,aAAa;QAC3B,KAAK;QACL,QAAQ;QACR,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACD,CAAC;AACrC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@downcity/city",
3
- "version": "0.2.200",
3
+ "version": "0.2.205",
4
4
  "description": "Downcity City runtime and City access SDK for services, actions, auth, env, and cities.",
5
5
  "type": "module",
6
6
  "main": "./bin/index.js",
@@ -41,7 +41,7 @@
41
41
  "typescript": "^6.0.3"
42
42
  },
43
43
  "dependencies": {
44
- "@downcity/type": "0.1.153",
44
+ "@downcity/type": "0.1.155",
45
45
  "ai": "^6.0.193",
46
46
  "drizzle-orm": "^0.45.2",
47
47
  "hono": "^4.12.23"
@@ -1,76 +0,0 @@
1
- /**
2
- * AI Provider 扣费协议。
3
- *
4
- * 关键说明(中文)
5
- * - Provider 自己理解上游 usage 与价格规则,并返回最终应扣金额。
6
- * - AIService 只负责在正确的生命周期内提交扣费,不理解 token/cache 等 provider 细节。
7
- * - Balance bridge 只暴露通用 charge 能力,避免 @downcity/city 反向依赖 @downcity/services。
8
- */
9
- import type { Context } from "../service.js";
10
- /**
11
- * Provider 计算出的单次扣费结果。
12
- */
13
- export interface AIProviderChargeLine {
14
- /**
15
- * 可选扣费用户 ID。
16
- *
17
- * 图片 result 轮询可能由 admin 或服务端代发,没有当前 user。
18
- * 这时 bill() 应从已保存任务归属中返回 user_id,AIService 会优先使用它。
19
- */
20
- user_id?: string;
21
- /** 扣费额度,单位为 credits。 */
22
- credits: number;
23
- /** 账单说明。 */
24
- note?: string;
25
- /** 外部引用 ID。 */
26
- ref?: string;
27
- /** 内部审计信息,不作为跨 provider 的公共 usage 协议。 */
28
- metadata?: Record<string, unknown>;
29
- }
30
- /**
31
- * AIService 提交给外部 Balance bridge 的扣费输入。
32
- */
33
- export interface AIBalanceChargeInput extends AIProviderChargeLine {
34
- /** 当前用户 ID。 */
35
- user_id: string;
36
- /** 可选幂等键;相同键的重复提交必须只产生一次扣费。 */
37
- idempotency_key?: string;
38
- }
39
- /**
40
- * AIService 依赖的最小 Balance bridge。
41
- */
42
- export interface AIBalanceBridge {
43
- /**
44
- * 执行余额前置检查。
45
- *
46
- * AIService 默认调用时不传 needed_credits,只拦截已经欠费的用户。
47
- */
48
- precheck?(user_id: string, needed_credits?: number): Promise<{
49
- credits: number;
50
- }>;
51
- /** 执行扣费并记录账单。 */
52
- charge(input: AIBalanceChargeInput): Promise<unknown>;
53
- }
54
- /**
55
- * Provider 或模型生成扣费行的方法。
56
- */
57
- export type AIProviderBillFn = (ctx: Context, output: unknown) => AIProviderChargeLine | Promise<AIProviderChargeLine | undefined> | undefined;
58
- /**
59
- * Provider action 可返回的带扣费普通输出。
60
- */
61
- export interface AIProviderChargedOutput<T = unknown> {
62
- /** 对外返回的原始 action 输出。 */
63
- output: T;
64
- /** Provider 已计算好的扣费结果。 */
65
- charge?: AIProviderChargeLine | Promise<AIProviderChargeLine | undefined> | undefined;
66
- }
67
- /**
68
- * Provider action 可返回的带扣费 Response 输出。
69
- */
70
- export interface AIProviderChargedResponse {
71
- /** 对外返回的 HTTP Response。 */
72
- response: Response;
73
- /** Provider 已计算好的扣费结果。 */
74
- charge?: AIProviderChargeLine | Promise<AIProviderChargeLine | undefined> | undefined;
75
- }
76
- //# sourceMappingURL=charge.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"charge.d.ts","sourceRoot":"","sources":["../../../src/service/ai/charge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAChE,eAAe;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAElF,iBAAiB;IACjB,MAAM,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvD;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,OAAO,KACZ,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;AAElF;;GAEG;AACH,MAAM,WAAW,uBAAuB,CAAC,CAAC,GAAG,OAAO;IAClD,yBAAyB;IACzB,MAAM,EAAE,CAAC,CAAC;IACV,0BAA0B;IAC1B,MAAM,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CACvF;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,2BAA2B;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,0BAA0B;IAC1B,MAAM,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CACvF"}
@@ -1,10 +0,0 @@
1
- /**
2
- * AI Provider 扣费协议。
3
- *
4
- * 关键说明(中文)
5
- * - Provider 自己理解上游 usage 与价格规则,并返回最终应扣金额。
6
- * - AIService 只负责在正确的生命周期内提交扣费,不理解 token/cache 等 provider 细节。
7
- * - Balance bridge 只暴露通用 charge 能力,避免 @downcity/city 反向依赖 @downcity/services。
8
- */
9
- export {};
10
- //# sourceMappingURL=charge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"charge.js","sourceRoot":"","sources":["../../../src/service/ai/charge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -1,69 +0,0 @@
1
- /**
2
- * AI 图片任务协议类型。
3
- *
4
- * 关键点(中文)
5
- * - AIService 固定 image_create / image_fetch / image_result 的返回协议。
6
- * - AIService 默认使用内置 async_jobs 表保存图片任务,Provider 只负责创建上游任务和抓取上游结果。
7
- */
8
- import type { UIMessage } from "ai";
9
- import type { AsyncJobRecord } from "../../types/AsyncJob.js";
10
- /** 图片任务状态。 */
11
- export type AIImageJobStatus = "queued" | "running" | "succeeded" | "failed";
12
- /** 图片任务扩展元数据。 */
13
- export interface AIImageJobMetadata {
14
- /** 扩展字段,由具体 Provider 自行约定。 */
15
- [key: string]: unknown;
16
- }
17
- /** image_create action 返回给 AIService 的固定协议。 */
18
- export interface AIImageProviderCreateResult {
19
- /** 图片任务 ID,对 AIService 不透明,由具体 Provider 生成或转发。 */
20
- job_id: string;
21
- /** 创建后的任务状态。 */
22
- status: AIImageJobStatus;
23
- /** 当前任务状态说明,便于客户端展示或排障。 */
24
- message?: string;
25
- /** 失败时返回的错误消息。 */
26
- error?: string;
27
- /** 建议客户端下一次查询 result 的间隔毫秒数。 */
28
- poll_after_ms?: number;
29
- /** 具体 Provider 返回的扩展元数据。 */
30
- metadata?: AIImageJobMetadata;
31
- }
32
- /** image_fetch action 返回给 AIService 的固定协议。 */
33
- export interface AIImageProviderFetchResult {
34
- /** 图片任务 ID。 */
35
- job_id: string;
36
- /** 当前任务状态。 */
37
- status: AIImageJobStatus;
38
- /** 成功时返回的 AI SDK UIMessage。 */
39
- result?: UIMessage;
40
- /** 失败时返回的错误消息。 */
41
- error?: string;
42
- /** 当前任务状态说明,便于客户端展示或排障。 */
43
- message?: string;
44
- /** 建议客户端下一次查询 result 的间隔毫秒数。 */
45
- poll_after_ms?: number;
46
- /** 具体 Provider 返回的扩展元数据。 */
47
- metadata?: AIImageJobMetadata;
48
- }
49
- /** image/create 返回给客户端的结果。 */
50
- export type UserImageJobCreateResult = AIImageProviderCreateResult;
51
- /** image/result 返回给客户端的结果。 */
52
- export type UserImageJobResult = AIImageProviderFetchResult;
53
- /** image/result 的查询输入。 */
54
- export interface UserImageJobResultInput {
55
- /** 图片任务 ID,由 image_create 返回。 */
56
- job_id: string;
57
- }
58
- /** Provider 在 image_fetch 中可读取的图片任务上下文。 */
59
- export interface AIImageJobContext {
60
- /** async_jobs 中保存的完整任务记录。 */
61
- record: AsyncJobRecord;
62
- /** image_create 时的原始输入。 */
63
- input: Record<string, unknown>;
64
- /** image_create / image_fetch 返回的 provider 状态。 */
65
- state?: AIImageJobMetadata;
66
- }
67
- /** 兼容命名:Provider fetch 与用户 result 使用相同固定结果协议。 */
68
- export type AIImageProviderResult = AIImageProviderFetchResult;
69
- //# sourceMappingURL=job-types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"job-types.d.ts","sourceRoot":"","sources":["../../../src/service/ai/job-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,cAAc;AACd,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE7E,iBAAiB;AACjB,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,+CAA+C;AAC/C,MAAM,WAAW,2BAA2B;IAC1C,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,MAAM,EAAE,gBAAgB,CAAC;IACzB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED,8CAA8C;AAC9C,MAAM,WAAW,0BAA0B;IACzC,eAAe;IACf,MAAM,EAAE,MAAM,CAAC;IACf,cAAc;IACd,MAAM,EAAE,gBAAgB,CAAC;IACzB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED,8BAA8B;AAC9B,MAAM,MAAM,wBAAwB,GAAG,2BAA2B,CAAC;AAEnE,8BAA8B;AAC9B,MAAM,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAE5D,0BAA0B;AAC1B,MAAM,WAAW,uBAAuB;IACtC,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,2CAA2C;AAC3C,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,MAAM,EAAE,cAAc,CAAC;IACvB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,kDAAkD;IAClD,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAED,iDAAiD;AACjD,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,CAAC"}
@@ -1,9 +0,0 @@
1
- /**
2
- * AI 图片任务协议类型。
3
- *
4
- * 关键点(中文)
5
- * - AIService 固定 image_create / image_fetch / image_result 的返回协议。
6
- * - AIService 默认使用内置 async_jobs 表保存图片任务,Provider 只负责创建上游任务和抓取上游结果。
7
- */
8
- export {};
9
- //# sourceMappingURL=job-types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"job-types.js","sourceRoot":"","sources":["../../../src/service/ai/job-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -1,143 +0,0 @@
1
- /**
2
- * AI Provider 模块。
3
- *
4
- * Provider 是第三方 AI 提供商的基类。
5
- * - 默认提供 OpenAI-compatible 的 text 实现。
6
- * - 子类通过覆盖 createClient 来绑定不同的 AI SDK provider。
7
- * - 需要其它模态(image / video / tts / asr)或自定义 openai 透传时,覆盖对应方法。
8
- */
9
- import type { UIMessage } from "ai";
10
- import type { CityModelReasoning } from "@downcity/type";
11
- import type { Context } from "../service.js";
12
- import type { AIProviderBillFn, AIProviderChargedOutput, AIProviderChargedResponse, AIProviderChargeLine } from "./charge.js";
13
- import type { AIImageProviderCreateResult, AIImageProviderFetchResult, AIImageProviderResult } from "./job-types.js";
14
- import type { ModelConfig, CityLanguageModelV3, ModelFallbackRule, OpenAICompatibleClient, OpenAICompatibleClientConfig, ProviderOptions } from "./types.js";
15
- import type { AIProviderOptions } from "../../types/AIReasoning.js";
16
- import type { CityProviderStreamCall, CityProviderStreamResult } from "../../types/CityLanguageModelRuntime.js";
17
- interface OpenAIActionInput {
18
- /** 多轮 UIMessage。 */
19
- messages?: UIMessage[];
20
- /** 单轮 prompt。 */
21
- prompt?: string;
22
- /** OpenAI function tools。 */
23
- tools?: Record<string, unknown>[];
24
- }
25
- /**
26
- * AI Provider 基类。
27
- *
28
- * 子类通过覆盖方法声明 action,model() 会自动收集并生成 ModelConfig。
29
- * 默认 text 使用 OpenAI-compatible 协议,CityModel 模型流统一由 stream 提供。
30
- */
31
- export declare abstract class Provider {
32
- /** Provider 唯一 ID。 */
33
- readonly id: string;
34
- /** 模型所需环境变量说明。 */
35
- readonly env?: Record<string, string>;
36
- /** Provider 的 baseURL(用于自动透传)。 */
37
- readonly baseURL?: string;
38
- /** Provider 的环境变量 key。 */
39
- readonly envKey?: string;
40
- /** 上游 API 实际模型 ID(自动透传时替换 body.model)。 */
41
- readonly passthroughModel?: string;
42
- constructor(options: ProviderOptions);
43
- /**
44
- * 创建 OpenAI-compatible chat client。
45
- *
46
- * 子类需要支持 text 或 CityModel stream 时必须覆盖。
47
- * 默认抛出错误。
48
- */
49
- protected createClient(config: OpenAICompatibleClientConfig): OpenAICompatibleClient;
50
- /**
51
- * 从输入中提取 prompt 文本。
52
- *
53
- * 子类可覆盖以支持多模态 messages 转文本。
54
- */
55
- protected extractPrompt(input: OpenAIActionInput): string;
56
- /**
57
- * 为一次完成的调用生成扣费草稿。
58
- *
59
- * 默认不返回扣费。真正扣款由 AIService 调用 BalanceService 完成。
60
- */
61
- protected bill(ctx: Context, output: unknown): AIProviderChargeLine | undefined;
62
- /** 创建默认 OpenAI-compatible chat model。 */
63
- private create_openai_compatible_model;
64
- /**
65
- * 执行一次 CityModel 标准模型流。
66
- *
67
- * 默认实现把调用交给 OpenAI-compatible chat model。Responses、Claude Messages、
68
- * Gemini 或自定义上游协议应覆盖此方法,并返回标准 LanguageModelV3 流事件。
69
- */
70
- protected stream(ctx: Context, call: CityProviderStreamCall): Promise<CityProviderStreamResult>;
71
- /**
72
- * 将输入解析成 prompt 或 messages。
73
- */
74
- private resolveActionInput;
75
- /**
76
- * 将 AIService 已解析的推理强度转换为当前 AI SDK Provider 的 providerOptions。
77
- *
78
- * 默认实现适用于 OpenAI-compatible Provider。Anthropic、Gemini 等字段结构不同的
79
- * Provider 应覆盖该方法,但不能重新读取或校验原始 reasoning_effort。
80
- */
81
- protected build_reasoning_provider_options(ctx: Context, model: CityLanguageModelV3): AIProviderOptions | undefined;
82
- /**
83
- * 文本生成 action(OpenAI-compatible 默认实现)。
84
- */
85
- text(ctx: Context): Promise<AIProviderChargedOutput<UIMessage>>;
86
- /**
87
- * 图片任务创建 action。
88
- *
89
- * 子类实现图片生成时覆盖,负责创建并启动 provider 侧图片任务。
90
- */
91
- image_create?(ctx: Context): Promise<AIImageProviderCreateResult>;
92
- /**
93
- * 图片任务抓取 action。
94
- *
95
- * 子类实现图片生成时覆盖,负责根据 provider 任务状态抓取上游结果。
96
- */
97
- image_fetch?(ctx: Context): Promise<AIImageProviderFetchResult>;
98
- /**
99
- * 图片任务查询 action。
100
- *
101
- * 该方法保留为类型兼容,AIService 图片能力默认使用 image_fetch。
102
- */
103
- image_result?(ctx: Context): Promise<AIImageProviderResult>;
104
- /**
105
- * 视频生成 action。
106
- */
107
- video?(ctx: Context): Promise<AIProviderChargedOutput<UIMessage>>;
108
- /**
109
- * 语音合成 action。
110
- */
111
- tts?(ctx: Context): Promise<AIProviderChargedResponse>;
112
- /**
113
- * 语音识别 action。
114
- */
115
- asr?(ctx: Context): Promise<AIProviderChargedResponse>;
116
- /**
117
- * OpenAI 兼容 /chat/completions action。
118
- *
119
- * 未覆盖时由 AIService 自动透传。
120
- */
121
- openai?(ctx: Context): Promise<AIProviderChargedResponse>;
122
- /**
123
- * 生成模型配置。
124
- *
125
- * 自动收集当前 Provider 实例上定义的 action 方法。
126
- */
127
- model(spec: {
128
- id: string;
129
- name: string;
130
- description?: string;
131
- /** 模型支持的总上下文窗口长度,单位为 token。 */
132
- context_window?: number;
133
- tags?: string[];
134
- meta?: Record<string, unknown>;
135
- /** 面向用户展示的价格说明列表;不参与实际扣费计算。 */
136
- price?: string[];
137
- reasoning?: CityModelReasoning;
138
- fallback?: ModelFallbackRule[];
139
- bill?: AIProviderBillFn;
140
- }): ModelConfig;
141
- }
142
- export {};
143
- //# sourceMappingURL=provider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/service/ai/provider.ts"],"names":[],"mappings":"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"}
@@ -1,221 +0,0 @@
1
- /**
2
- * AI Provider 模块。
3
- *
4
- * Provider 是第三方 AI 提供商的基类。
5
- * - 默认提供 OpenAI-compatible 的 text 实现。
6
- * - 子类通过覆盖 createClient 来绑定不同的 AI SDK provider。
7
- * - 需要其它模态(image / video / tts / asr)或自定义 openai 透传时,覆盖对应方法。
8
- */
9
- import { convertToModelMessages, generateText } from "ai";
10
- import { buildAssistantMessage, buildToolSet, readRequiredEnv, resolveUpstreamModel, } from "./helpers.js";
11
- import { read_resolved_reasoning } from "./reasoning.js";
12
- // ===========================================================================
13
- // Provider 基类
14
- // ===========================================================================
15
- /**
16
- * AI Provider 基类。
17
- *
18
- * 子类通过覆盖方法声明 action,model() 会自动收集并生成 ModelConfig。
19
- * 默认 text 使用 OpenAI-compatible 协议,CityModel 模型流统一由 stream 提供。
20
- */
21
- export class Provider {
22
- /** Provider 唯一 ID。 */
23
- id;
24
- /** 模型所需环境变量说明。 */
25
- env;
26
- /** Provider 的 baseURL(用于自动透传)。 */
27
- baseURL;
28
- /** Provider 的环境变量 key。 */
29
- envKey;
30
- /** 上游 API 实际模型 ID(自动透传时替换 body.model)。 */
31
- passthroughModel;
32
- constructor(options) {
33
- this.id = options.id;
34
- this.env = options.env ?? (options.envKey ? { [options.envKey]: `${options.id} API Key` } : undefined);
35
- this.baseURL = options.baseURL;
36
- this.envKey = options.envKey;
37
- this.passthroughModel = options.passthroughModel;
38
- }
39
- /**
40
- * 创建 OpenAI-compatible chat client。
41
- *
42
- * 子类需要支持 text 或 CityModel stream 时必须覆盖。
43
- * 默认抛出错误。
44
- */
45
- createClient(config) {
46
- throw new Error(`Provider ${this.id} does not support language models`);
47
- }
48
- /**
49
- * 从输入中提取 prompt 文本。
50
- *
51
- * 子类可覆盖以支持多模态 messages 转文本。
52
- */
53
- extractPrompt(input) {
54
- if (typeof input.prompt === "string")
55
- return input.prompt;
56
- return input.messages
57
- ?.find((message) => message.role === "user")
58
- ?.parts?.find((part) => part.type === "text")
59
- ?.text ?? "";
60
- }
61
- /**
62
- * 为一次完成的调用生成扣费草稿。
63
- *
64
- * 默认不返回扣费。真正扣款由 AIService 调用 BalanceService 完成。
65
- */
66
- bill(ctx, output) {
67
- return undefined;
68
- }
69
- /** 创建默认 OpenAI-compatible chat model。 */
70
- create_openai_compatible_model(ctx) {
71
- if (!this.envKey) {
72
- throw new Error(`Provider ${this.id} is missing envKey`);
73
- }
74
- const api_key = readRequiredEnv(ctx, this.envKey);
75
- const base_url = this.baseURL ?? "https://api.openai.com/v1";
76
- const upstream_model = resolveUpstreamModel(ctx, this.passthroughModel ?? "");
77
- return this.createClient({ apiKey: api_key, baseURL: base_url, name: this.id }).chat(upstream_model);
78
- }
79
- /**
80
- * 执行一次 CityModel 标准模型流。
81
- *
82
- * 默认实现把调用交给 OpenAI-compatible chat model。Responses、Claude Messages、
83
- * Gemini 或自定义上游协议应覆盖此方法,并返回标准 LanguageModelV3 流事件。
84
- */
85
- async stream(ctx, call) {
86
- const model = this.create_openai_compatible_model(ctx);
87
- const provider_options = this.build_reasoning_provider_options(ctx, model);
88
- return model.doStream({
89
- ...call,
90
- ...(provider_options ? { providerOptions: provider_options } : {}),
91
- });
92
- }
93
- /**
94
- * 将输入解析成 prompt 或 messages。
95
- */
96
- async resolveActionInput(input) {
97
- const tools = buildToolSet(input.tools);
98
- if (Array.isArray(input.messages) && input.messages.length > 0) {
99
- const messages = tools
100
- ? await convertToModelMessages(input.messages, { tools })
101
- : await convertToModelMessages(input.messages);
102
- return tools ? { tools, messages } : { messages };
103
- }
104
- return {
105
- prompt: this.extractPrompt(input),
106
- };
107
- }
108
- /**
109
- * 将 AIService 已解析的推理强度转换为当前 AI SDK Provider 的 providerOptions。
110
- *
111
- * 默认实现适用于 OpenAI-compatible Provider。Anthropic、Gemini 等字段结构不同的
112
- * Provider 应覆盖该方法,但不能重新读取或校验原始 reasoning_effort。
113
- */
114
- build_reasoning_provider_options(ctx, model) {
115
- const reasoning = read_resolved_reasoning(ctx);
116
- if (!reasoning)
117
- return undefined;
118
- const provider = typeof model === "object" && model !== null && "provider" in model
119
- ? model.provider
120
- : undefined;
121
- const provider_id = typeof provider === "string"
122
- ? provider.split(".")[0]?.trim()
123
- : undefined;
124
- if (!provider_id) {
125
- throw new Error(`Provider ${this.id} cannot resolve AI SDK provider id`);
126
- }
127
- return {
128
- [provider_id]: {
129
- reasoningEffort: reasoning.effort,
130
- },
131
- };
132
- }
133
- /**
134
- * 文本生成 action(OpenAI-compatible 默认实现)。
135
- */
136
- async text(ctx) {
137
- const input = ctx.input;
138
- const resolved_input = await this.resolveActionInput(input);
139
- const model = this.create_openai_compatible_model(ctx);
140
- const provider_options = this.build_reasoning_provider_options(ctx, model);
141
- if ("messages" in resolved_input) {
142
- const result = await generateText({
143
- model,
144
- messages: resolved_input.messages,
145
- ...("tools" in resolved_input ? { tools: resolved_input.tools } : {}),
146
- ...(provider_options ? { providerOptions: provider_options } : {}),
147
- });
148
- return buildAssistantMessage(result.text, ctx, {
149
- finishReason: result.finishReason,
150
- usage: result.usage,
151
- ...("tools" in resolved_input ? { toolCalls: result.toolCalls } : {}),
152
- });
153
- }
154
- const result = await generateText({
155
- model,
156
- prompt: resolved_input.prompt,
157
- ...(provider_options ? { providerOptions: provider_options } : {}),
158
- });
159
- return buildAssistantMessage(result.text, ctx, {
160
- finishReason: result.finishReason,
161
- usage: result.usage,
162
- });
163
- }
164
- /**
165
- * 生成模型配置。
166
- *
167
- * 自动收集当前 Provider 实例上定义的 action 方法。
168
- */
169
- model(spec) {
170
- const actions = {};
171
- const has_language_model = this.stream !== Provider.prototype.stream ||
172
- this.createClient !== Provider.prototype.createClient;
173
- const all_modalities = [
174
- "text",
175
- "image_create",
176
- "image_fetch",
177
- "image_result",
178
- "video",
179
- "tts",
180
- "asr",
181
- "openai",
182
- ];
183
- for (const modality of all_modalities) {
184
- const fn = this[modality];
185
- if (typeof fn !== "function")
186
- continue;
187
- // text 默认由基类实现,只有子类显式覆盖或提供了 createClient 才暴露。
188
- if (modality === "text") {
189
- const is_overridden = fn !== Provider.prototype[modality];
190
- const has_create_client = this.createClient !== Provider.prototype.createClient;
191
- if (!is_overridden && !has_create_client)
192
- continue;
193
- }
194
- actions[modality] = fn.bind(this);
195
- }
196
- return {
197
- id: spec.id,
198
- provider_id: this.id,
199
- name: spec.name,
200
- description: spec.description,
201
- context_window: spec.context_window,
202
- tags: spec.tags,
203
- ...(spec.price ? { price: [...spec.price] } : {}),
204
- meta: spec.meta,
205
- reasoning: spec.reasoning,
206
- env: this.env,
207
- baseURL: this.baseURL,
208
- envKey: this.envKey,
209
- passthroughModel: this.passthroughModel,
210
- fallback: spec.fallback,
211
- actions,
212
- ...(has_language_model ? {
213
- language_model: {
214
- stream: (ctx, call) => this.stream(ctx, call),
215
- },
216
- } : {}),
217
- bill: spec.bill ?? this.bill.bind(this),
218
- };
219
- }
220
- }
221
- //# sourceMappingURL=provider.js.map