@downcity/agent 1.1.43 → 1.1.62

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 (256) hide show
  1. package/README.md +11 -12
  2. package/bin/agent/Agent.d.ts +31 -16
  3. package/bin/agent/Agent.d.ts.map +1 -1
  4. package/bin/agent/Agent.js +47 -63
  5. package/bin/agent/Agent.js.map +1 -1
  6. package/bin/agent/RemoteAgent.d.ts +6 -6
  7. package/bin/agent/RemoteAgent.d.ts.map +1 -1
  8. package/bin/agent/RemoteAgent.js +377 -267
  9. package/bin/agent/RemoteAgent.js.map +1 -1
  10. package/bin/config/AgentInitializer.d.ts +5 -5
  11. package/bin/config/AgentInitializer.d.ts.map +1 -1
  12. package/bin/config/AgentInitializer.js +15 -13
  13. package/bin/config/AgentInitializer.js.map +1 -1
  14. package/bin/config/Config.d.ts +9 -30
  15. package/bin/config/Config.d.ts.map +1 -1
  16. package/bin/config/Config.js +23 -70
  17. package/bin/config/Config.js.map +1 -1
  18. package/bin/config/Defaults.d.ts.map +1 -1
  19. package/bin/config/Defaults.js +1 -9
  20. package/bin/config/Defaults.js.map +1 -1
  21. package/bin/config/DowncitySchema.d.ts.map +1 -1
  22. package/bin/config/DowncitySchema.js +4 -112
  23. package/bin/config/DowncitySchema.js.map +1 -1
  24. package/bin/config/ExecutionBinding.d.ts +1 -16
  25. package/bin/config/ExecutionBinding.d.ts.map +1 -1
  26. package/bin/config/ExecutionBinding.js +2 -22
  27. package/bin/config/ExecutionBinding.js.map +1 -1
  28. package/bin/config/Paths.d.ts +4 -43
  29. package/bin/config/Paths.d.ts.map +1 -1
  30. package/bin/config/Paths.js +10 -30
  31. package/bin/config/Paths.js.map +1 -1
  32. package/bin/config/PlatformPaths.d.ts +0 -4
  33. package/bin/config/PlatformPaths.d.ts.map +1 -1
  34. package/bin/config/PlatformPaths.js +5 -1
  35. package/bin/config/PlatformPaths.js.map +1 -1
  36. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
  37. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +0 -4
  38. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
  39. package/bin/executor/composer/system/default/InitPrompts.d.ts +1 -1
  40. package/bin/executor/composer/system/default/InitPrompts.js +1 -1
  41. package/bin/executor/composer/system/default/SystemDomain.js +1 -1
  42. package/bin/executor/composer/system/default/assets/core.prompt.d.ts +1 -1
  43. package/bin/executor/composer/system/default/assets/core.prompt.js +1 -1
  44. package/bin/executor/composer/system/default/assets/init/PROFILE.md.d.ts +1 -1
  45. package/bin/executor/composer/system/default/assets/init/PROFILE.md.d.ts.map +1 -1
  46. package/bin/executor/composer/system/default/assets/init/PROFILE.md.js +1 -1
  47. package/bin/executor/composer/system/default/assets/init/PROFILE.md.js.map +1 -1
  48. package/bin/executor/composer/system/default/assets/plugin.prompt.d.ts +1 -1
  49. package/bin/executor/composer/system/default/assets/plugin.prompt.js +1 -1
  50. package/bin/executor/composer/system/default/assets/task.prompt.d.ts +1 -1
  51. package/bin/executor/composer/system/default/assets/task.prompt.js +1 -1
  52. package/bin/executor/messages/ChatMessageMarkupTypes.d.ts +1 -1
  53. package/bin/executor/messages/ChatMessageMarkupTypes.js +1 -1
  54. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts +1 -2
  55. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +1 -1
  56. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +17 -56
  57. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
  58. package/bin/executor/tools/shell/ShellToolBridge.js +1 -1
  59. package/bin/executor/tools/shell/ShellToolBridge.js.map +1 -1
  60. package/bin/executor/tools/shell/ShellToolDefinition.d.ts +2 -2
  61. package/bin/executor/tools/shell/ShellToolFormatting.d.ts +1 -1
  62. package/bin/executor/tools/shell/ShellToolFormatting.js +9 -9
  63. package/bin/executor/tools/shell/ShellToolFormatting.js.map +1 -1
  64. package/bin/executor/tools/shell/ShellToolSchemas.d.ts +7 -75
  65. package/bin/executor/tools/shell/ShellToolSchemas.d.ts.map +1 -1
  66. package/bin/executor/types/SessionHistoryMeta.d.ts +5 -24
  67. package/bin/executor/types/SessionHistoryMeta.d.ts.map +1 -1
  68. package/bin/executor/types/SessionHistoryMeta.js +1 -1
  69. package/bin/executor/types/SessionRun.d.ts +1 -1
  70. package/bin/index.d.ts +5 -6
  71. package/bin/index.d.ts.map +1 -1
  72. package/bin/index.js +6 -5
  73. package/bin/index.js.map +1 -1
  74. package/bin/model/CityModelAdapter.d.ts +23 -0
  75. package/bin/model/CityModelAdapter.d.ts.map +1 -0
  76. package/bin/model/CityModelAdapter.js +338 -0
  77. package/bin/model/CityModelAdapter.js.map +1 -0
  78. package/bin/plugin/core/PluginCommandRequest.d.ts +1 -1
  79. package/bin/plugin/core/PluginCommandRequest.js +1 -1
  80. package/bin/plugin/core/PluginLocalExecution.d.ts.map +1 -1
  81. package/bin/plugin/core/PluginLocalExecution.js +4 -8
  82. package/bin/plugin/core/PluginLocalExecution.js.map +1 -1
  83. package/bin/plugin/types/PluginApi.d.ts +1 -1
  84. package/bin/rpc/Client.d.ts +104 -0
  85. package/bin/rpc/Client.d.ts.map +1 -0
  86. package/bin/rpc/Client.js +300 -0
  87. package/bin/rpc/Client.js.map +1 -0
  88. package/bin/rpc/Server.d.ts +41 -0
  89. package/bin/rpc/Server.d.ts.map +1 -0
  90. package/bin/rpc/Server.js +164 -0
  91. package/bin/rpc/Server.js.map +1 -0
  92. package/bin/runtime/host/daemon/Api.d.ts +1 -1
  93. package/bin/runtime/host/daemon/Client.d.ts +1 -1
  94. package/bin/runtime/host/daemon/Client.d.ts.map +1 -1
  95. package/bin/runtime/host/daemon/Client.js +30 -20
  96. package/bin/runtime/host/daemon/Client.js.map +1 -1
  97. package/bin/runtime/host/daemon/Paths.d.ts +1 -1
  98. package/bin/runtime/host/daemon/Paths.js +1 -1
  99. package/bin/runtime/host/daemon/ProjectSetup.js +2 -2
  100. package/bin/runtime/server/http/control/OverviewRoutes.js +1 -1
  101. package/bin/runtime/server/http/control/OverviewRoutes.js.map +1 -1
  102. package/bin/session/Session.d.ts +1 -0
  103. package/bin/session/Session.d.ts.map +1 -1
  104. package/bin/session/Session.js +32 -6
  105. package/bin/session/Session.js.map +1 -1
  106. package/bin/session/SessionTitle.d.ts +49 -0
  107. package/bin/session/SessionTitle.d.ts.map +1 -0
  108. package/bin/session/SessionTitle.js +130 -0
  109. package/bin/session/SessionTitle.js.map +1 -0
  110. package/bin/session/browse/Browse.d.ts +2 -1
  111. package/bin/session/browse/Browse.d.ts.map +1 -1
  112. package/bin/session/browse/Browse.js +18 -15
  113. package/bin/session/browse/Browse.js.map +1 -1
  114. package/bin/session/index.d.ts +3 -2
  115. package/bin/session/index.d.ts.map +1 -1
  116. package/bin/session/index.js +3 -2
  117. package/bin/session/index.js.map +1 -1
  118. package/bin/session/storage/Metadata.d.ts +4 -0
  119. package/bin/session/storage/Metadata.d.ts.map +1 -1
  120. package/bin/session/storage/Metadata.js +12 -25
  121. package/bin/session/storage/Metadata.js.map +1 -1
  122. package/bin/session/storage/Paths.d.ts +0 -4
  123. package/bin/session/storage/Paths.d.ts.map +1 -1
  124. package/bin/session/storage/Paths.js +0 -6
  125. package/bin/session/storage/Paths.js.map +1 -1
  126. package/bin/session/storage/Persistence.d.ts.map +1 -1
  127. package/bin/session/storage/Persistence.js +1 -4
  128. package/bin/session/storage/Persistence.js.map +1 -1
  129. package/bin/types/agent/AgentTypes.d.ts +32 -57
  130. package/bin/types/agent/AgentTypes.d.ts.map +1 -1
  131. package/bin/types/config/AgentProject.d.ts +7 -6
  132. package/bin/types/config/AgentProject.d.ts.map +1 -1
  133. package/bin/types/config/DowncityConfig.d.ts +11 -69
  134. package/bin/types/config/DowncityConfig.d.ts.map +1 -1
  135. package/bin/types/config/ExecutionBinding.d.ts +4 -4
  136. package/bin/types/config/ExecutionBinding.js +1 -1
  137. package/bin/types/config/LlmConfig.d.ts +1 -1
  138. package/bin/types/config/Start.d.ts +3 -0
  139. package/bin/types/config/Start.d.ts.map +1 -1
  140. package/bin/types/config/Start.js +2 -0
  141. package/bin/types/config/Start.js.map +1 -1
  142. package/bin/types/runtime/auth/AuthPermission.js +2 -2
  143. package/bin/types/runtime/auth/AuthPermission.js.map +1 -1
  144. package/bin/types/runtime/host/Store.d.ts +10 -227
  145. package/bin/types/runtime/host/Store.d.ts.map +1 -1
  146. package/bin/types/runtime/host/Store.js +7 -0
  147. package/bin/types/runtime/host/Store.js.map +1 -1
  148. package/bin/types/runtime/http/InlineInstant.d.ts +1 -1
  149. package/bin/types/runtime/platform/Platform.d.ts +7 -7
  150. package/bin/types/runtime/platform/Platform.d.ts.map +1 -1
  151. package/bin/types/runtime/platform/PlatformGateway.d.ts +2 -2
  152. package/bin/types/runtime/platform/PlatformGateway.d.ts.map +1 -1
  153. package/bin/utils/Time.d.ts +0 -1
  154. package/bin/utils/Time.d.ts.map +1 -1
  155. package/bin/utils/Time.js +0 -7
  156. package/bin/utils/Time.js.map +1 -1
  157. package/bin/utils/storage/index.d.ts +0 -1
  158. package/bin/utils/storage/index.d.ts.map +1 -1
  159. package/bin/utils/storage/index.js +0 -6
  160. package/bin/utils/storage/index.js.map +1 -1
  161. package/package.json +22 -23
  162. package/src/agent/Agent.ts +57 -73
  163. package/src/agent/RemoteAgent.ts +515 -345
  164. package/src/config/AgentInitializer.ts +15 -13
  165. package/src/config/Config.ts +28 -85
  166. package/src/config/Defaults.ts +1 -9
  167. package/src/config/DowncitySchema.ts +4 -114
  168. package/src/config/ExecutionBinding.ts +2 -24
  169. package/src/config/Paths.ts +10 -43
  170. package/src/config/PlatformPaths.ts +5 -1
  171. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +0 -4
  172. package/src/executor/composer/system/default/InitPrompts.ts +1 -1
  173. package/src/executor/composer/system/default/SystemDomain.ts +1 -1
  174. package/src/executor/composer/system/default/assets/core.prompt.ts +1 -1
  175. package/src/executor/composer/system/default/assets/core.prompt.ts.txt +1 -1
  176. package/src/executor/composer/system/default/assets/init/PROFILE.md.ts +1 -1
  177. package/src/executor/composer/system/default/assets/init/PROFILE.md.ts.txt +1 -2
  178. package/src/executor/composer/system/default/assets/plugin.prompt.ts +1 -1
  179. package/src/executor/composer/system/default/assets/plugin.prompt.ts.txt +18 -18
  180. package/src/executor/composer/system/default/assets/task.prompt.ts +1 -1
  181. package/src/executor/composer/system/default/assets/task.prompt.ts.txt +1 -1
  182. package/src/executor/messages/ChatMessageMarkupTypes.ts +1 -1
  183. package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +17 -57
  184. package/src/executor/tools/shell/ShellToolBridge.ts +1 -1
  185. package/src/executor/tools/shell/ShellToolFormatting.ts +9 -9
  186. package/src/executor/types/SessionHistoryMeta.ts +5 -25
  187. package/src/executor/types/SessionRun.ts +1 -1
  188. package/src/index.ts +12 -19
  189. package/src/model/CityModelAdapter.ts +384 -0
  190. package/src/plugin/core/PluginCommandRequest.ts +1 -1
  191. package/src/plugin/core/PluginLocalExecution.ts +4 -8
  192. package/src/plugin/types/PluginApi.ts +1 -1
  193. package/src/rpc/Client.ts +467 -0
  194. package/src/rpc/Server.ts +302 -0
  195. package/src/runtime/host/daemon/Api.ts +1 -1
  196. package/src/runtime/host/daemon/Client.ts +44 -22
  197. package/src/runtime/host/daemon/Paths.ts +1 -1
  198. package/src/runtime/host/daemon/ProjectSetup.ts +2 -2
  199. package/src/runtime/server/http/control/OverviewRoutes.ts +1 -1
  200. package/src/session/Session.ts +40 -6
  201. package/src/session/SessionTitle.ts +192 -0
  202. package/src/session/browse/Browse.ts +22 -13
  203. package/src/session/index.ts +5 -1
  204. package/src/session/storage/Metadata.ts +14 -29
  205. package/src/session/storage/Paths.ts +0 -10
  206. package/src/session/storage/Persistence.ts +1 -4
  207. package/src/types/agent/AgentTypes.ts +33 -62
  208. package/src/types/config/AgentProject.ts +7 -6
  209. package/src/types/config/DowncityConfig.ts +11 -70
  210. package/src/types/config/ExecutionBinding.ts +4 -4
  211. package/src/types/config/LlmConfig.ts +1 -1
  212. package/src/types/config/Start.ts +3 -0
  213. package/src/types/runtime/auth/AuthPermission.ts +2 -2
  214. package/src/types/runtime/host/Store.ts +10 -235
  215. package/src/types/runtime/http/InlineInstant.ts +1 -1
  216. package/src/types/runtime/platform/Platform.ts +7 -7
  217. package/src/types/runtime/platform/PlatformGateway.ts +2 -2
  218. package/src/utils/Time.ts +0 -6
  219. package/src/utils/storage/index.ts +0 -7
  220. package/tsconfig.json +1 -0
  221. package/tsconfig.tsbuildinfo +1 -1
  222. package/bin/config/ConfigEnvResolver.d.ts +0 -22
  223. package/bin/config/ConfigEnvResolver.d.ts.map +0 -1
  224. package/bin/config/ConfigEnvResolver.js +0 -41
  225. package/bin/config/ConfigEnvResolver.js.map +0 -1
  226. package/bin/runtime/server/rpc/Server.d.ts +0 -18
  227. package/bin/runtime/server/rpc/Server.d.ts.map +0 -1
  228. package/bin/runtime/server/rpc/Server.js +0 -315
  229. package/bin/runtime/server/rpc/Server.js.map +0 -1
  230. package/bin/runtime/transport/rpc/Client.d.ts +0 -13
  231. package/bin/runtime/transport/rpc/Client.d.ts.map +0 -1
  232. package/bin/runtime/transport/rpc/Client.js +0 -98
  233. package/bin/runtime/transport/rpc/Client.js.map +0 -1
  234. package/bin/runtime/transport/rpc/Paths.d.ts +0 -14
  235. package/bin/runtime/transport/rpc/Paths.d.ts.map +0 -1
  236. package/bin/runtime/transport/rpc/Paths.js +0 -42
  237. package/bin/runtime/transport/rpc/Paths.js.map +0 -1
  238. package/bin/runtime/transport/rpc/Transport.d.ts +0 -21
  239. package/bin/runtime/transport/rpc/Transport.d.ts.map +0 -1
  240. package/bin/runtime/transport/rpc/Transport.js +0 -30
  241. package/bin/runtime/transport/rpc/Transport.js.map +0 -1
  242. package/bin/types/common/ResolvedConfigValue.d.ts +0 -12
  243. package/bin/types/common/ResolvedConfigValue.d.ts.map +0 -1
  244. package/bin/types/common/ResolvedConfigValue.js +0 -2
  245. package/bin/types/common/ResolvedConfigValue.js.map +0 -1
  246. package/bin/types/runtime/rpc/LocalRpc.d.ts +0 -69
  247. package/bin/types/runtime/rpc/LocalRpc.d.ts.map +0 -1
  248. package/bin/types/runtime/rpc/LocalRpc.js +0 -9
  249. package/bin/types/runtime/rpc/LocalRpc.js.map +0 -1
  250. package/src/config/ConfigEnvResolver.ts +0 -52
  251. package/src/runtime/server/rpc/Server.ts +0 -408
  252. package/src/runtime/transport/rpc/Client.ts +0 -113
  253. package/src/runtime/transport/rpc/Paths.ts +0 -50
  254. package/src/runtime/transport/rpc/Transport.ts +0 -43
  255. package/src/types/common/ResolvedConfigValue.ts +0 -16
  256. package/src/types/runtime/rpc/LocalRpc.ts +0 -72
@@ -0,0 +1,384 @@
1
+ /**
2
+ * CityModel 到 AI SDK LanguageModel 的适配模块。
3
+ *
4
+ * 关键点(中文)
5
+ * - Agent 对外可以接收 CityModel,但 executor 内部仍只处理 AI SDK LanguageModel。
6
+ * - 适配逻辑集中在这里,避免 City 协议散落到 session/executor 各处。
7
+ * - 这里不依赖 @downcity/city,只依赖 @downcity/type 的共享协议。
8
+ */
9
+
10
+ import {
11
+ CITY_MODEL_INVOKER,
12
+ isCityModel,
13
+ type CityModel,
14
+ type CityModelInvokeInput,
15
+ } from "@downcity/type";
16
+ import type { LanguageModel, UIMessage, UIMessageChunk } from "ai";
17
+
18
+ /**
19
+ * Agent SDK 可接受的模型输入。
20
+ */
21
+ export type AgentModel = LanguageModel | CityModel;
22
+
23
+ type ProviderPromptMessage = {
24
+ /**
25
+ * 模型消息角色。
26
+ */
27
+ role?: string;
28
+
29
+ /**
30
+ * 模型消息内容。
31
+ */
32
+ content?: unknown;
33
+ };
34
+
35
+ type ProviderStreamController = ReadableStreamDefaultController<Record<string, unknown>>;
36
+ type ProviderContentPart = Record<string, unknown>;
37
+
38
+ function normalizeFinishReason(input: unknown): {
39
+ unified: "stop" | "length" | "content-filter" | "tool-calls" | "error" | "other";
40
+ raw: string | undefined;
41
+ } {
42
+ const text = typeof input === "string" ? input : "";
43
+ if (text === "stop" || text === "length" || text === "content-filter" || text === "tool-calls" || text === "error") {
44
+ return { unified: text, raw: text };
45
+ }
46
+ return { unified: "stop", raw: text || "stop" };
47
+ }
48
+
49
+ function stringifyToolInput(input: unknown): string {
50
+ if (typeof input === "string") return input;
51
+ try {
52
+ return JSON.stringify(input ?? {});
53
+ } catch {
54
+ return "{}";
55
+ }
56
+ }
57
+
58
+ function textFromProviderContent(content: unknown): string {
59
+ if (typeof content === "string") return content;
60
+ if (!Array.isArray(content)) return "";
61
+ return content
62
+ .filter((part) => part && typeof part === "object" && (part as { type?: unknown }).type === "text")
63
+ .map((part) => String((part as { text?: unknown }).text ?? ""))
64
+ .join("\n")
65
+ .trim();
66
+ }
67
+
68
+ function fileUrlFromProviderPart(part: Record<string, unknown>): string {
69
+ const data = part.data;
70
+ if (data instanceof URL) return data.toString();
71
+ if (typeof data === "string") return data;
72
+ return "";
73
+ }
74
+
75
+ function providerContentToUiParts(content: unknown): UIMessage["parts"] {
76
+ if (!Array.isArray(content)) {
77
+ return [{ type: "text", text: textFromProviderContent(content) }];
78
+ }
79
+
80
+ const parts: UIMessage["parts"] = [];
81
+ for (const part of content) {
82
+ if (!part || typeof part !== "object") continue;
83
+ const record = part as Record<string, unknown>;
84
+ if (record.type === "text") {
85
+ parts.push({ type: "text", text: String(record.text ?? "") });
86
+ continue;
87
+ }
88
+ if (record.type === "reasoning") {
89
+ parts.push({ type: "reasoning", text: String(record.text ?? "") });
90
+ continue;
91
+ }
92
+ if (record.type === "file") {
93
+ const url = fileUrlFromProviderPart(record);
94
+ if (!url) continue;
95
+ parts.push({
96
+ type: "file",
97
+ mediaType: String(record.mediaType ?? "application/octet-stream"),
98
+ filename: typeof record.filename === "string" ? record.filename : undefined,
99
+ url,
100
+ });
101
+ continue;
102
+ }
103
+ if (record.type === "tool-call") {
104
+ parts.push({
105
+ type: "dynamic-tool",
106
+ toolName: String(record.toolName ?? ""),
107
+ toolCallId: String(record.toolCallId ?? ""),
108
+ state: "input-available",
109
+ input: record.input,
110
+ providerExecuted: Boolean(record.providerExecuted),
111
+ });
112
+ }
113
+ }
114
+ return parts;
115
+ }
116
+
117
+ function providerPromptToMessages(prompt: unknown): UIMessage[] {
118
+ if (!Array.isArray(prompt)) return [];
119
+ return prompt
120
+ .map((message, index): UIMessage | null => {
121
+ if (!message || typeof message !== "object") return null;
122
+ const item = message as ProviderPromptMessage;
123
+ const role = item.role === "system" || item.role === "assistant" ? item.role : "user";
124
+ const parts = providerContentToUiParts(item.content);
125
+ return {
126
+ id: `city-model-message-${String(index)}`,
127
+ role,
128
+ parts,
129
+ };
130
+ })
131
+ .filter((message): message is UIMessage => Boolean(message));
132
+ }
133
+
134
+ function providerOptionsToInput(options: Record<string, unknown>): CityModelInvokeInput {
135
+ return {
136
+ messages: providerPromptToMessages(options.prompt),
137
+ tools: options.tools,
138
+ toolChoice: options.toolChoice,
139
+ providerOptions: options.providerOptions,
140
+ };
141
+ }
142
+
143
+ function textFromUiMessage(message: UIMessage): string {
144
+ return message.parts
145
+ .filter((part) => part.type === "text")
146
+ .map((part) => String((part as { text?: unknown }).text ?? ""))
147
+ .join("\n")
148
+ .trim();
149
+ }
150
+
151
+ function uiMessageToProviderContent(message: UIMessage): ProviderContentPart[] {
152
+ return message.parts.flatMap((part): ProviderContentPart[] => {
153
+ if (part.type === "text") {
154
+ return [{ type: "text", text: String((part as { text?: unknown }).text ?? "") }];
155
+ }
156
+ if (part.type === "reasoning") {
157
+ return [{ type: "reasoning", text: String((part as { text?: unknown }).text ?? "") }];
158
+ }
159
+ if (part.type === "dynamic-tool") {
160
+ const toolPart = part as {
161
+ toolCallId?: unknown;
162
+ toolName?: unknown;
163
+ input?: unknown;
164
+ providerExecuted?: unknown;
165
+ };
166
+ return [{
167
+ type: "tool-call",
168
+ toolCallId: String(toolPart.toolCallId ?? ""),
169
+ toolName: String(toolPart.toolName ?? ""),
170
+ input: stringifyToolInput(toolPart.input),
171
+ providerExecuted: Boolean(toolPart.providerExecuted),
172
+ }];
173
+ }
174
+ return [];
175
+ });
176
+ }
177
+
178
+ function enqueueFinish(
179
+ controller: ProviderStreamController,
180
+ finishReason: unknown,
181
+ ): void {
182
+ controller.enqueue({
183
+ type: "finish",
184
+ finishReason: normalizeFinishReason(finishReason),
185
+ usage: {
186
+ inputTokens: {
187
+ total: undefined,
188
+ noCache: undefined,
189
+ cacheRead: undefined,
190
+ cacheWrite: undefined,
191
+ },
192
+ outputTokens: {
193
+ total: undefined,
194
+ text: undefined,
195
+ reasoning: undefined,
196
+ },
197
+ },
198
+ });
199
+ }
200
+
201
+ function enqueueProviderParts(
202
+ controller: ProviderStreamController,
203
+ parts: Record<string, unknown>[],
204
+ state: {
205
+ /**
206
+ * 当前流是否已经发出 stream-start。
207
+ */
208
+ sawStart: boolean;
209
+
210
+ /**
211
+ * 当前流是否已经发出 finish。
212
+ */
213
+ sawFinish: boolean;
214
+ },
215
+ ): void {
216
+ for (const part of parts) {
217
+ if (part.type !== "stream-start" && !state.sawStart) {
218
+ controller.enqueue({ type: "stream-start", warnings: [] });
219
+ state.sawStart = true;
220
+ }
221
+ if (part.type === "stream-start") state.sawStart = true;
222
+ if (part.type === "finish") state.sawFinish = true;
223
+ controller.enqueue(part);
224
+ }
225
+ }
226
+
227
+ function mapUiChunkToProviderParts(chunk: UIMessageChunk): ProviderContentPart[] {
228
+ switch (chunk.type) {
229
+ case "start":
230
+ return [{ type: "stream-start", warnings: [] }];
231
+ case "text-start":
232
+ return [{ type: "text-start", id: chunk.id }];
233
+ case "text-delta":
234
+ return [{ type: "text-delta", id: chunk.id, delta: chunk.delta }];
235
+ case "text-end":
236
+ return [{ type: "text-end", id: chunk.id }];
237
+ case "reasoning-start":
238
+ return [{ type: "reasoning-start", id: chunk.id }];
239
+ case "reasoning-delta":
240
+ return [{ type: "reasoning-delta", id: chunk.id, delta: chunk.delta }];
241
+ case "reasoning-end":
242
+ return [{ type: "reasoning-end", id: chunk.id }];
243
+ case "tool-input-start":
244
+ return [{
245
+ type: "tool-input-start",
246
+ id: chunk.toolCallId,
247
+ toolName: chunk.toolName,
248
+ providerExecuted: chunk.providerExecuted,
249
+ dynamic: chunk.dynamic,
250
+ }];
251
+ case "tool-input-delta":
252
+ return [{
253
+ type: "tool-input-delta",
254
+ id: chunk.toolCallId,
255
+ delta: chunk.inputTextDelta,
256
+ }];
257
+ case "tool-input-available":
258
+ return [{
259
+ type: "tool-call",
260
+ toolCallId: chunk.toolCallId,
261
+ toolName: chunk.toolName,
262
+ input: stringifyToolInput(chunk.input),
263
+ providerExecuted: chunk.providerExecuted,
264
+ dynamic: chunk.dynamic,
265
+ }];
266
+ case "tool-output-available":
267
+ return [{
268
+ type: "tool-result",
269
+ toolCallId: chunk.toolCallId,
270
+ toolName: "",
271
+ output: { type: "json", value: chunk.output },
272
+ providerExecuted: chunk.providerExecuted,
273
+ dynamic: chunk.dynamic,
274
+ }];
275
+ case "error":
276
+ return [{ type: "error", error: new Error(chunk.errorText) }];
277
+ default:
278
+ return [];
279
+ }
280
+ }
281
+
282
+ function cityModelToLanguageModel(model: CityModel): LanguageModel {
283
+ const invoker = model[CITY_MODEL_INVOKER];
284
+ const languageModel = {
285
+ specificationVersion: "v3",
286
+ provider: "downcity",
287
+ modelId: model.id,
288
+ supportedUrls: {},
289
+ async doGenerate(options) {
290
+ const message = await invoker.text(providerOptionsToInput(options as Record<string, unknown>));
291
+ return {
292
+ content: uiMessageToProviderContent(message),
293
+ finishReason: normalizeFinishReason("stop"),
294
+ usage: {
295
+ inputTokens: {
296
+ total: undefined,
297
+ noCache: undefined,
298
+ cacheRead: undefined,
299
+ cacheWrite: undefined,
300
+ },
301
+ outputTokens: {
302
+ total: undefined,
303
+ text: undefined,
304
+ reasoning: undefined,
305
+ },
306
+ },
307
+ response: {
308
+ modelId: model.id,
309
+ },
310
+ warnings: [],
311
+ };
312
+ },
313
+ async doStream(options) {
314
+ const cityStream = await invoker.stream(providerOptionsToInput(options as Record<string, unknown>));
315
+ return {
316
+ stream: new ReadableStream({
317
+ async start(controller: ProviderStreamController) {
318
+ const reader = cityStream.getReader();
319
+ const state = {
320
+ sawStart: false,
321
+ sawFinish: false,
322
+ };
323
+ try {
324
+ while (true) {
325
+ const { done, value } = await reader.read();
326
+ if (done) break;
327
+ const parts = mapUiChunkToProviderParts(value);
328
+ enqueueProviderParts(controller, parts, state);
329
+ }
330
+ if (!state.sawStart) controller.enqueue({ type: "stream-start", warnings: [] });
331
+ if (!state.sawFinish) enqueueFinish(controller, "stop");
332
+ controller.close();
333
+ } catch (error) {
334
+ controller.enqueue({ type: "error", error });
335
+ if (!state.sawFinish) enqueueFinish(controller, "error");
336
+ controller.close();
337
+ } finally {
338
+ reader.releaseLock();
339
+ }
340
+ },
341
+ }),
342
+ response: {
343
+ modelId: model.id,
344
+ },
345
+ };
346
+ },
347
+ };
348
+
349
+ return languageModel as unknown as LanguageModel;
350
+ }
351
+
352
+ /**
353
+ * 将 Agent 可接受的模型输入归一为 AI SDK LanguageModel。
354
+ */
355
+ export function normalizeAgentModel(model: AgentModel): LanguageModel {
356
+ if (isCityModel(model)) return cityModelToLanguageModel(model);
357
+ return model;
358
+ }
359
+
360
+ /**
361
+ * 从 Agent 模型输入推导展示标签。
362
+ */
363
+ export function inferAgentModelLabel(model: AgentModel | undefined): string | undefined {
364
+ if (!model) return undefined;
365
+ if (isCityModel(model)) return model.name || model.id;
366
+ if (typeof model !== "object") return undefined;
367
+ const record = model as Record<string, unknown>;
368
+ const candidates = [
369
+ record.modelId,
370
+ record.model,
371
+ record.id,
372
+ record.name,
373
+ record.label,
374
+ ];
375
+ for (const candidate of candidates) {
376
+ const label = typeof candidate === "string" ? candidate.trim() : "";
377
+ if (label) return label;
378
+ }
379
+ const constructorName =
380
+ model.constructor && typeof model.constructor.name === "string"
381
+ ? model.constructor.name.trim()
382
+ : "";
383
+ return constructorName || "configured-model";
384
+ }
@@ -2,7 +2,7 @@
2
2
  * PluginCommandRequest:统一 plugin runtime command 请求解析模块。
3
3
  *
4
4
  * 关键点(中文)
5
- * - 统一收口 HTTP / RPC 两种入口的请求体解析。
5
+ * - 统一收口当前 HTTP 入口的请求体解析。
6
6
  * - plugin runtime 远程调用统一走 runtime command 协议,不再让 action 自带 HTTP route。
7
7
  * - ActionSchedule 参数(`schedule` / `delay` / `time`)也在这里一次性归一化。
8
8
  */
@@ -9,7 +9,7 @@
9
9
 
10
10
  import path from "node:path";
11
11
  import { logger as defaultLogger } from "@/utils/logger/Logger.js";
12
- import { loadAgentEnvSnapshot, loadDowncityConfig } from "@/config/Config.js";
12
+ import { loadDowncityConfig, resolveAgentEnv } from "@/config/Config.js";
13
13
  import { isPluginEnabled } from "@/plugin/core/Activation.js";
14
14
  import { findPluginByName } from "@/plugin/core/PluginCatalog.js";
15
15
  import {
@@ -30,12 +30,8 @@ import type { AgentContext } from "@/types/runtime/agent/AgentContext.js";
30
30
  */
31
31
  export function createLocalPluginCommandContext(projectRoot: string): PluginCommandContext {
32
32
  const rootPath = path.resolve(String(projectRoot || "").trim() || ".");
33
- const env = loadAgentEnvSnapshot(rootPath);
34
- const config = loadDowncityConfig(rootPath, {
35
- projectEnv: env,
36
- agentEnv: env,
37
- globalEnv: {},
38
- });
33
+ const env = resolveAgentEnv(rootPath);
34
+ const config = loadDowncityConfig(rootPath);
39
35
 
40
36
  defaultLogger.bindProjectRoot(rootPath);
41
37
 
@@ -47,7 +43,7 @@ export function createLocalPluginCommandContext(projectRoot: string): PluginComm
47
43
  env,
48
44
  paths: createAgentPathRuntime(
49
45
  rootPath,
50
- String(config.name || "").trim() || path.basename(rootPath) || "agent",
46
+ String(config.id || "").trim() || path.basename(rootPath) || "agent",
51
47
  ),
52
48
  pluginConfig: createAgentPluginConfigRuntime(rootPath),
53
49
  };
@@ -155,7 +155,7 @@ export interface PluginCliBaseOptions {
155
155
  */
156
156
  json?: boolean;
157
157
  /**
158
- * agent 名称(从 managed agent registry 解析到项目路径)。
158
+ * agent id(从 managed agent registry 解析到项目路径)。
159
159
  */
160
160
  agent?: string;
161
161
  }