@lark-base-open/base-database-cli 1.3.9 → 1.4.3

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 (320) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +119 -15
  3. package/THIRD_PARTY_LICENSES.json +1662 -0
  4. package/config-schema.json +64 -3
  5. package/data/template-hmr-scripts.json +9 -0
  6. package/data/template-index-html/17e698eef687ece8f1628e3e2c4801da5e7233faa87076b3424acde8df57b825.html +24 -0
  7. package/dist/agent-tools-guide.d.ts +29 -0
  8. package/dist/agent-tools-guide.d.ts.map +1 -0
  9. package/dist/agent-tools-guide.js +169 -0
  10. package/dist/agent-tools-guide.js.map +1 -0
  11. package/dist/agent-tools-skill.d.ts +16 -0
  12. package/dist/agent-tools-skill.d.ts.map +1 -0
  13. package/dist/agent-tools-skill.js +183 -0
  14. package/dist/agent-tools-skill.js.map +1 -0
  15. package/dist/agent-tools.d.ts +20 -0
  16. package/dist/agent-tools.d.ts.map +1 -0
  17. package/dist/agent-tools.js +137 -0
  18. package/dist/agent-tools.js.map +1 -0
  19. package/dist/ai-functions.d.ts +10 -0
  20. package/dist/ai-functions.d.ts.map +1 -1
  21. package/dist/ai-functions.js +264 -212
  22. package/dist/ai-functions.js.map +1 -1
  23. package/dist/app-builder/core.d.mts +37 -0
  24. package/dist/app-builder/core.d.mts.map +1 -0
  25. package/dist/app-builder/core.mjs +673 -0
  26. package/dist/app-builder/core.mjs.map +1 -0
  27. package/dist/app-builder/package.json +1 -0
  28. package/dist/app-builder/schema.d.ts +4 -0
  29. package/dist/app-builder/schema.d.ts.map +1 -0
  30. package/dist/app-builder/schema.js +72 -0
  31. package/dist/app-builder/schema.js.map +1 -0
  32. package/dist/archive.d.ts +22 -2
  33. package/dist/archive.d.ts.map +1 -1
  34. package/dist/archive.js +311 -74
  35. package/dist/archive.js.map +1 -1
  36. package/dist/auth.d.ts +2 -2
  37. package/dist/auth.d.ts.map +1 -1
  38. package/dist/auth.js +13 -8
  39. package/dist/auth.js.map +1 -1
  40. package/dist/build-server.d.ts +25 -0
  41. package/dist/build-server.d.ts.map +1 -0
  42. package/dist/build-server.js +32 -0
  43. package/dist/build-server.js.map +1 -0
  44. package/dist/business-update-notice.d.ts +37 -0
  45. package/dist/business-update-notice.d.ts.map +1 -0
  46. package/dist/business-update-notice.js +24 -0
  47. package/dist/business-update-notice.js.map +1 -0
  48. package/dist/check.d.ts +11 -0
  49. package/dist/check.d.ts.map +1 -1
  50. package/dist/check.js +85 -15
  51. package/dist/check.js.map +1 -1
  52. package/dist/cloud-build-diagnostic.d.ts +9 -0
  53. package/dist/cloud-build-diagnostic.d.ts.map +1 -0
  54. package/dist/cloud-build-diagnostic.js +65 -0
  55. package/dist/cloud-build-diagnostic.js.map +1 -0
  56. package/dist/config.d.ts +6 -0
  57. package/dist/config.d.ts.map +1 -1
  58. package/dist/config.js +41 -11
  59. package/dist/config.js.map +1 -1
  60. package/dist/contract-extractor.d.ts +21 -0
  61. package/dist/contract-extractor.d.ts.map +1 -0
  62. package/dist/contract-extractor.js +260 -0
  63. package/dist/contract-extractor.js.map +1 -0
  64. package/dist/contract-worker.d.ts +12 -0
  65. package/dist/contract-worker.d.ts.map +1 -0
  66. package/dist/contract-worker.js +90 -0
  67. package/dist/contract-worker.js.map +1 -0
  68. package/dist/dependency-policy.d.ts.map +1 -1
  69. package/dist/dependency-policy.js +6 -1
  70. package/dist/dependency-policy.js.map +1 -1
  71. package/dist/deploy.d.ts +20 -1
  72. package/dist/deploy.d.ts.map +1 -1
  73. package/dist/deploy.js +181 -52
  74. package/dist/deploy.js.map +1 -1
  75. package/dist/dev-bootstrap.d.ts +5 -0
  76. package/dist/dev-bootstrap.d.ts.map +1 -0
  77. package/dist/dev-bootstrap.js +185 -0
  78. package/dist/dev-bootstrap.js.map +1 -0
  79. package/dist/dev-events.d.ts +24 -0
  80. package/dist/dev-events.d.ts.map +1 -0
  81. package/dist/dev-events.js +67 -0
  82. package/dist/dev-events.js.map +1 -0
  83. package/dist/dev-pairing.d.ts +4 -0
  84. package/dist/dev-pairing.d.ts.map +1 -0
  85. package/dist/dev-pairing.js +54 -0
  86. package/dist/dev-pairing.js.map +1 -0
  87. package/dist/dev-url.d.ts +4 -0
  88. package/dist/dev-url.d.ts.map +1 -0
  89. package/dist/dev-url.js +29 -0
  90. package/dist/dev-url.js.map +1 -0
  91. package/dist/dev-vite.d.ts +9 -0
  92. package/dist/dev-vite.d.ts.map +1 -0
  93. package/dist/dev-vite.js +237 -0
  94. package/dist/dev-vite.js.map +1 -0
  95. package/dist/dev-watch.d.ts +33 -0
  96. package/dist/dev-watch.d.ts.map +1 -0
  97. package/dist/dev-watch.js +246 -0
  98. package/dist/dev-watch.js.map +1 -0
  99. package/dist/dev.d.ts +24 -0
  100. package/dist/dev.d.ts.map +1 -0
  101. package/dist/dev.js +244 -0
  102. package/dist/dev.js.map +1 -0
  103. package/dist/development-pairing.generated.d.ts +12 -0
  104. package/dist/development-pairing.generated.d.ts.map +1 -0
  105. package/dist/development-pairing.generated.js +13 -0
  106. package/dist/development-pairing.generated.js.map +1 -0
  107. package/dist/diagnostic-platforms.d.ts +3 -0
  108. package/dist/diagnostic-platforms.d.ts.map +1 -0
  109. package/dist/diagnostic-platforms.js +3 -0
  110. package/dist/diagnostic-platforms.js.map +1 -0
  111. package/dist/diagnostic-schema.d.ts +151 -0
  112. package/dist/diagnostic-schema.d.ts.map +1 -0
  113. package/dist/diagnostic-schema.js +129 -0
  114. package/dist/diagnostic-schema.js.map +1 -0
  115. package/dist/diagnostics.d.ts +78 -0
  116. package/dist/diagnostics.d.ts.map +1 -0
  117. package/dist/diagnostics.js +333 -0
  118. package/dist/diagnostics.js.map +1 -0
  119. package/dist/distribution-commands.d.ts.map +1 -1
  120. package/dist/distribution-commands.js +6 -2
  121. package/dist/distribution-commands.js.map +1 -1
  122. package/dist/distribution-npm.d.ts +2 -2
  123. package/dist/distribution-npm.d.ts.map +1 -1
  124. package/dist/distribution-npm.js +14 -1
  125. package/dist/distribution-npm.js.map +1 -1
  126. package/dist/environment-variables.d.ts.map +1 -1
  127. package/dist/environment-variables.js +2 -1
  128. package/dist/environment-variables.js.map +1 -1
  129. package/dist/function-contracts.d.ts +40 -0
  130. package/dist/function-contracts.d.ts.map +1 -0
  131. package/dist/function-contracts.js +357 -0
  132. package/dist/function-contracts.js.map +1 -0
  133. package/dist/function-description.d.ts +11 -4
  134. package/dist/function-description.d.ts.map +1 -1
  135. package/dist/function-description.js +22 -12
  136. package/dist/function-description.js.map +1 -1
  137. package/dist/function-input-types.d.ts +6 -4
  138. package/dist/function-input-types.d.ts.map +1 -1
  139. package/dist/function-input-types.js +97 -135
  140. package/dist/function-input-types.js.map +1 -1
  141. package/dist/function-params.d.ts +53 -0
  142. package/dist/function-params.d.ts.map +1 -0
  143. package/dist/function-params.js +184 -0
  144. package/dist/function-params.js.map +1 -0
  145. package/dist/function-schema.d.ts +14 -0
  146. package/dist/function-schema.d.ts.map +1 -1
  147. package/dist/function-schema.js +99 -9
  148. package/dist/function-schema.js.map +1 -1
  149. package/dist/init-journal.d.ts +1 -0
  150. package/dist/init-journal.d.ts.map +1 -1
  151. package/dist/init-journal.js +21 -7
  152. package/dist/init-journal.js.map +1 -1
  153. package/dist/init.d.ts +1 -0
  154. package/dist/init.d.ts.map +1 -1
  155. package/dist/init.js +55 -5
  156. package/dist/init.js.map +1 -1
  157. package/dist/lark-cli-error.d.ts +13 -2
  158. package/dist/lark-cli-error.d.ts.map +1 -1
  159. package/dist/lark-cli-error.js +54 -13
  160. package/dist/lark-cli-error.js.map +1 -1
  161. package/dist/lark-cli-passthrough.d.ts +9 -0
  162. package/dist/lark-cli-passthrough.d.ts.map +1 -0
  163. package/dist/lark-cli-passthrough.js +101 -0
  164. package/dist/lark-cli-passthrough.js.map +1 -0
  165. package/dist/lark-cli.d.ts +5 -2
  166. package/dist/lark-cli.d.ts.map +1 -1
  167. package/dist/lark-cli.js +96 -29
  168. package/dist/lark-cli.js.map +1 -1
  169. package/dist/legacy-function-input-renderer.d.ts +6 -0
  170. package/dist/legacy-function-input-renderer.d.ts.map +1 -0
  171. package/dist/legacy-function-input-renderer.js +175 -0
  172. package/dist/legacy-function-input-renderer.js.map +1 -0
  173. package/dist/link-guard-check.d.ts +12 -0
  174. package/dist/link-guard-check.d.ts.map +1 -0
  175. package/dist/link-guard-check.js +138 -0
  176. package/dist/link-guard-check.js.map +1 -0
  177. package/dist/managed-agent-docs.d.ts +14 -0
  178. package/dist/managed-agent-docs.d.ts.map +1 -0
  179. package/dist/managed-agent-docs.js +172 -0
  180. package/dist/managed-agent-docs.js.map +1 -0
  181. package/dist/mutation-schema.d.ts +6 -0
  182. package/dist/mutation-schema.d.ts.map +1 -1
  183. package/dist/mutation-schema.js +6 -0
  184. package/dist/mutation-schema.js.map +1 -1
  185. package/dist/mutation.d.ts +4 -1
  186. package/dist/mutation.d.ts.map +1 -1
  187. package/dist/mutation.js +17 -2
  188. package/dist/mutation.js.map +1 -1
  189. package/dist/npm.d.ts +1 -0
  190. package/dist/npm.d.ts.map +1 -1
  191. package/dist/npm.js +28 -0
  192. package/dist/npm.js.map +1 -1
  193. package/dist/preview-receipt.d.ts +0 -2
  194. package/dist/preview-receipt.d.ts.map +1 -1
  195. package/dist/preview-receipt.js +0 -28
  196. package/dist/preview-receipt.js.map +1 -1
  197. package/dist/process.d.ts +1 -0
  198. package/dist/process.d.ts.map +1 -1
  199. package/dist/process.js +25 -0
  200. package/dist/process.js.map +1 -1
  201. package/dist/program.d.ts.map +1 -1
  202. package/dist/program.js +239 -26
  203. package/dist/program.js.map +1 -1
  204. package/dist/project-build.d.ts +2 -1
  205. package/dist/project-build.d.ts.map +1 -1
  206. package/dist/project-build.js +53 -16
  207. package/dist/project-build.js.map +1 -1
  208. package/dist/project-capabilities.d.ts +8 -0
  209. package/dist/project-capabilities.d.ts.map +1 -0
  210. package/dist/project-capabilities.js +47 -0
  211. package/dist/project-capabilities.js.map +1 -0
  212. package/dist/project-context.d.ts +66 -0
  213. package/dist/project-context.d.ts.map +1 -1
  214. package/dist/project-context.js +68 -6
  215. package/dist/project-context.js.map +1 -1
  216. package/dist/project-layout.d.ts +11 -0
  217. package/dist/project-layout.d.ts.map +1 -1
  218. package/dist/project-layout.js +63 -1
  219. package/dist/project-layout.js.map +1 -1
  220. package/dist/public-exports.d.ts +5 -0
  221. package/dist/public-exports.d.ts.map +1 -0
  222. package/dist/public-exports.js +76 -0
  223. package/dist/public-exports.js.map +1 -0
  224. package/dist/public-sql-error.d.ts +3 -1
  225. package/dist/public-sql-error.d.ts.map +1 -1
  226. package/dist/public-sql-error.js +5 -2
  227. package/dist/public-sql-error.js.map +1 -1
  228. package/dist/pull.d.ts +1 -0
  229. package/dist/pull.d.ts.map +1 -1
  230. package/dist/pull.js +103 -20
  231. package/dist/pull.js.map +1 -1
  232. package/dist/sdk-codegen.d.ts +16 -0
  233. package/dist/sdk-codegen.d.ts.map +1 -0
  234. package/dist/sdk-codegen.js +181 -0
  235. package/dist/sdk-codegen.js.map +1 -0
  236. package/dist/sdk-install.d.ts +4 -0
  237. package/dist/sdk-install.d.ts.map +1 -0
  238. package/dist/sdk-install.js +33 -0
  239. package/dist/sdk-install.js.map +1 -0
  240. package/dist/skill-frontmatter.d.ts +5 -0
  241. package/dist/skill-frontmatter.d.ts.map +1 -0
  242. package/dist/skill-frontmatter.js +28 -0
  243. package/dist/skill-frontmatter.js.map +1 -0
  244. package/dist/skill.d.ts +2 -1
  245. package/dist/skill.d.ts.map +1 -1
  246. package/dist/skill.js +18 -12
  247. package/dist/skill.js.map +1 -1
  248. package/dist/source-format.d.ts +10 -0
  249. package/dist/source-format.d.ts.map +1 -0
  250. package/dist/source-format.js +49 -0
  251. package/dist/source-format.js.map +1 -0
  252. package/dist/types.d.ts +6 -0
  253. package/dist/types.d.ts.map +1 -1
  254. package/dist/unified-functions.d.ts +22 -0
  255. package/dist/unified-functions.d.ts.map +1 -0
  256. package/dist/unified-functions.js +114 -0
  257. package/dist/unified-functions.js.map +1 -0
  258. package/dist/updates.d.ts +13 -1
  259. package/dist/updates.d.ts.map +1 -1
  260. package/dist/updates.js +65 -29
  261. package/dist/updates.js.map +1 -1
  262. package/dist/workspace-fingerprint.d.ts.map +1 -1
  263. package/dist/workspace-fingerprint.js +5 -0
  264. package/dist/workspace-fingerprint.js.map +1 -1
  265. package/package.json +17 -5
  266. package/skills/lark-base-database/SKILL.md +21 -55
  267. package/skills/lark-base-database/references/agent-tool-design.md +181 -0
  268. package/skills/lark-base-database/references/agent-tools.md +101 -0
  269. package/skills/lark-base-database/references/ai-function.md +80 -186
  270. package/skills/lark-base-database/references/database-function-limitations.md +12 -4
  271. package/skills/lark-base-database/references/database-function.md +49 -21
  272. package/skills/lark-base-database/references/development.md +81 -109
  273. package/skills/lark-base-database/references/environment-variables.md +2 -2
  274. package/skills/lark-base-database/references/faas.md +43 -16
  275. package/skills/lark-base-database/references/file-transfer.md +10 -33
  276. package/skills/lark-base-database/references/frontend-design-guide.md +1 -1
  277. package/skills/lark-base-database/references/legacy-ai-function.md +120 -0
  278. package/skills/lark-base-database/references/legacy-development.md +156 -0
  279. package/skills/lark-base-database/references/legacy-file-transfer.md +68 -0
  280. package/skills/lark-base-database/references/mutations.md +38 -29
  281. package/skills/lark-base-database/references/notifications.md +1 -1
  282. package/skills/lark-base-database/references/permission-design.md +11 -5
  283. package/skills/lark-base-database/references/release.md +22 -7
  284. package/skills/lark-base-database/references/verification.md +55 -16
  285. package/skills/lark-base-database/references/workspace-migration.md +86 -0
  286. package/skills/lark-base-database/references/workspace.md +55 -44
  287. package/templates/database-starter/README.md +2 -0
  288. package/templates/database-starter/database-functions/README.md +2 -2
  289. package/templates/database-starter/mutations/README.md +2 -2
  290. package/templates/database-starter/page/README.md +5 -4
  291. package/templates/database-starter/page/src/examples/ai-function/TextStreamOperation.tsx +6 -6
  292. package/templates/database-starter/page/src/lib/attachment-image.tsx +19 -5
  293. package/templates/database-starter/page/src/lib/database-runtime-attachment.test.ts +124 -5
  294. package/templates/database-starter/page/src/lib/database-runtime.test.ts +2 -2
  295. package/templates/database-starter/page/src/lib/database-runtime.ts +77 -13
  296. package/templates/database-starter/server-functions/scripts/run-tsc.mjs +3 -2
  297. package/templates/database-starter-v2/README.md +25 -0
  298. package/templates/database-starter-v2/base-app.config.ts +10 -0
  299. package/templates/database-starter-v2/database-functions/README.md +1 -0
  300. package/templates/database-starter-v2/gitignore +6 -0
  301. package/templates/database-starter-v2/mutations/README.md +1 -0
  302. package/templates/database-starter-v2/package-lock.json +2239 -0
  303. package/templates/database-starter-v2/package.json +18 -0
  304. package/templates/database-starter-v2/page/index.html +2 -0
  305. package/templates/database-starter-v2/page/package.json +25 -0
  306. package/templates/database-starter-v2/page/src/App.tsx +12 -0
  307. package/templates/database-starter-v2/page/src/generated/README.md +1 -0
  308. package/templates/database-starter-v2/page/src/index.css +1 -0
  309. package/templates/database-starter-v2/page/src/lib/date-time.ts +61 -0
  310. package/templates/database-starter-v2/page/src/main.tsx +6 -0
  311. package/templates/database-starter-v2/page/tsconfig.json +19 -0
  312. package/templates/database-starter-v2/page/vite.config.ts +3 -0
  313. package/templates/database-starter-v2/prettierignore +3 -0
  314. package/templates/database-starter-v2/server/functions/README.md +1 -0
  315. package/templates/database-starter-v2/server/functions/hello/contract.ts +5 -0
  316. package/templates/database-starter-v2/server/functions/hello/index.ts +7 -0
  317. package/templates/database-starter-v2/server/functions/hello/meta.json +1 -0
  318. package/templates/database-starter-v2/server/generated/runtime-profile.ts +5 -0
  319. package/templates/database-starter-v2/server/package.json +17 -0
  320. package/templates/database-starter-v2/server/tsconfig.json +14 -0
@@ -1,9 +1,12 @@
1
1
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, } from 'node:fs';
2
2
  import { basename, dirname, join, resolve } from 'node:path';
3
+ import { assertFunctionResults, functionEnv, getFunction, listFunctions, putFunctions, } from './unified-functions.js';
4
+ import { responseFunctionHints, AGENT_TOOL_DESIGN_REFERENCE, } from './function-params.js';
5
+ import { normalizeFunctionInputSchema } from './function-schema.js';
3
6
  import { readConfig } from './config.js';
4
7
  import { assertProjectRuntimeProfile, ONLINE_RUNTIME_PROFILE, } from './environment.js';
5
8
  import { LarkCliError } from './lark-cli-error.js';
6
- import { responseData, runLarkCli } from './lark-cli.js';
9
+ import { responseData, runLarkCli, resolveLarkProfileEnvironment, } from './lark-cli.js';
7
10
  // 服务端对 AI Function 管理接口(list/get/upsert/delete/validate/update/usage)做用户级 feature gate,
8
11
  // 未开通时返回 800004011 "ai function feature is not enabled"。这不是 scope 缺失,重新登录无法解决;
9
12
  // 这里把它翻译成可执行的降级路径,避免 Agent 把它当作权限错误循环授权。
@@ -11,11 +14,13 @@ export const AI_FUNCTION_FEATURE_NOT_ENABLED_CODE = 800004011;
11
14
  export const AI_FUNCTION_FEATURE_NOT_ENABLED_MESSAGE = 'AI Function management is not enabled for the current user (800004011). This is a feature gate, not a missing scope, so `auth login` does not help. Publish without AI Functions via `deploy --skip-ai-functions` (or remove ai/) and report the AI Function part as blocked.';
12
15
  export function isAIFunctionFeatureNotEnabled(error) {
13
16
  return (error instanceof LarkCliError &&
14
- Number(error.details.code) === AI_FUNCTION_FEATURE_NOT_ENABLED_CODE);
17
+ Number(error.details.code) === AI_FUNCTION_FEATURE_NOT_ENABLED_CODE &&
18
+ /ai function feature is not enabled|AI Function management is not enabled/i.test(error.details.message));
15
19
  }
16
- function aiFunctionAccessError(error) {
20
+ export function aiFunctionAccessError(error) {
17
21
  if (error instanceof LarkCliError &&
18
- Number(error.details.code) === AI_FUNCTION_FEATURE_NOT_ENABLED_CODE) {
22
+ Number(error.details.code) === AI_FUNCTION_FEATURE_NOT_ENABLED_CODE &&
23
+ /ai function feature is not enabled|AI Function management is not enabled/i.test(error.details.message)) {
19
24
  return new LarkCliError({
20
25
  ...error.details,
21
26
  message: AI_FUNCTION_FEATURE_NOT_ENABLED_MESSAGE,
@@ -32,14 +37,89 @@ function runAIFunctionApi(args, env, cwd) {
32
37
  }
33
38
  }
34
39
  // AI Function 是「功能清单」里的一类声明式资源(function_type=4):model/System Prompt/能力配置都在
35
- // ai/<functionKey>/meta.json 里维护,随 deploy 走 OpenAPI 全量覆盖同步。不进 site.zip(不是部署代码,是配置)。
40
+ // ai/<functionKey>/meta.json 里维护,随 deploy 走 OpenAPI 全量覆盖同步。随 site.zip 保存源声明,pull 以远端草稿详情恢复配置。
36
41
  const FUNCTION_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
37
- const MAX_AI_FUNCTIONS = 200;
38
42
  const AI_FUNCTIONS_DIR = 'ai';
39
43
  const CAPABILITY_TYPES = new Set(['text', 'vision', 'image', 'video']);
44
+ function parseAIJSON(source) {
45
+ const json = JSON;
46
+ return JSON.parse(source, (_key, value, context) => {
47
+ if (typeof value !== 'number')
48
+ return value;
49
+ if (json.rawJSON && context?.source)
50
+ return json.rawJSON(context.source);
51
+ if (!Number.isFinite(value) ||
52
+ (Number.isInteger(value) && !Number.isSafeInteger(value)))
53
+ throw new RangeError('Exact AI numeric defaults require Node.js 22');
54
+ return value;
55
+ });
56
+ }
40
57
  function stripPlatformManagedFields(config) {
41
58
  const normalized = { ...config };
42
59
  delete normalized.limits;
60
+ delete normalized.output_mode;
61
+ if (normalized.variables !== undefined) {
62
+ process.stderr.write('Warning: AI config.variables 已弃用,请将 meta.json 迁移为 config.input_schema。\n');
63
+ }
64
+ if (normalized.input_schema === undefined) {
65
+ const properties = Object.create(null);
66
+ const required = [];
67
+ const variables = normalized.variables ?? [];
68
+ if (!Array.isArray(variables))
69
+ throw new Error('AI variables must be an array');
70
+ for (const variable of [...variables].sort((a, b) => String(a?.name) < String(b?.name)
71
+ ? -1
72
+ : String(a?.name) > String(b?.name)
73
+ ? 1
74
+ : 0)) {
75
+ if (!variable ||
76
+ typeof variable.name !== 'string' ||
77
+ !['string', 'number', 'boolean', 'object'].includes(variable.type))
78
+ throw new Error('Invalid legacy AI variable declaration');
79
+ if (Object.hasOwn(properties, variable.name))
80
+ throw new Error(`Duplicate AI variable: ${variable.name}`);
81
+ const property = variable.type === 'object'
82
+ ? { oneOf: [{ type: 'object' }, { type: 'array' }] }
83
+ : { type: variable.type };
84
+ if (typeof variable.description === 'string')
85
+ property.description = variable.description;
86
+ if (variable.default !== undefined && variable.default !== '') {
87
+ try {
88
+ const value = variable.type === 'string'
89
+ ? variable.default
90
+ : JSON.parse(variable.default);
91
+ if (variable.type === 'object'
92
+ ? value === null || typeof value !== 'object'
93
+ : typeof value !== variable.type)
94
+ throw new Error('type');
95
+ property.default =
96
+ variable.type === 'string' ? value : parseAIJSON(variable.default);
97
+ }
98
+ catch (error) {
99
+ if (error instanceof RangeError)
100
+ throw error;
101
+ process.stderr.write(`Warning: AI variable ${variable.name}: invalid default omitted.\n`);
102
+ }
103
+ }
104
+ properties[variable.name] = property;
105
+ if (variable.required === true && !Object.hasOwn(property, 'default'))
106
+ required.push(variable.name);
107
+ }
108
+ normalized.input_schema = {
109
+ type: 'object',
110
+ properties,
111
+ ...(required.length ? { required } : {}),
112
+ additionalProperties: true,
113
+ };
114
+ }
115
+ else {
116
+ normalizeFunctionInputSchema(normalized.input_schema, 'AI config.input_schema');
117
+ }
118
+ if (!normalized.input_schema ||
119
+ typeof normalized.input_schema !== 'object' ||
120
+ normalized.input_schema.type !== 'object')
121
+ throw new Error('AI input_schema must have type object');
122
+ delete normalized.variables;
43
123
  const text = config.text;
44
124
  if (text && typeof text === 'object' && !Array.isArray(text)) {
45
125
  const rest = { ...text };
@@ -58,7 +138,7 @@ function readAIFunctionMeta(path) {
58
138
  !FUNCTION_ID_PATTERN.test(functionKey)) {
59
139
  throw new Error(`Invalid AI Function key: ${functionKey}`);
60
140
  }
61
- const manifest = JSON.parse(readFileSync(path, 'utf8'));
141
+ const manifest = parseAIJSON(readFileSync(path, 'utf8'));
62
142
  if (typeof manifest.name !== 'string' || manifest.name === '') {
63
143
  throw new Error(`AI Function name must be a non-empty string: ${path}`);
64
144
  }
@@ -66,7 +146,9 @@ function readAIFunctionMeta(path) {
66
146
  typeof manifest.description !== 'string') {
67
147
  throw new Error(`AI Function description must be a string: ${path}`);
68
148
  }
69
- if (!manifest.config || typeof manifest.config !== 'object') {
149
+ if (!manifest.config ||
150
+ typeof manifest.config !== 'object' ||
151
+ Array.isArray(manifest.config)) {
70
152
  throw new Error(`AI Function config must be an object: ${path}`);
71
153
  }
72
154
  const config = stripPlatformManagedFields(manifest.config);
@@ -81,114 +163,116 @@ function readAIFunctionMeta(path) {
81
163
  name: manifest.name,
82
164
  };
83
165
  }
84
- // collectLocalAIFunctions 读取 ai/<key>/meta.json 全集(本地声明),供 deploy 全量覆盖同步与 sync 命令共用。
85
- export function collectLocalAIFunctions(workspace) {
166
+ /** Inventory does not parse AI configuration, so skip can still bypass invalid AI metadata. */
167
+ export function localAIFunctionKeys(workspace) {
86
168
  const root = aiFunctionsRoot(workspace);
87
- if (!existsSync(root)) {
169
+ if (!existsSync(root))
88
170
  return [];
89
- }
90
- const items = [];
91
- const seen = new Set();
92
- for (const entry of readdirSync(root, { withFileTypes: true })) {
93
- if (!entry.isDirectory())
94
- continue;
171
+ return readdirSync(root, { withFileTypes: true })
172
+ .filter((entry) => {
95
173
  const path = join(root, entry.name, 'meta.json');
96
- if (!existsSync(path) || !statSync(path).isFile())
97
- continue;
98
- const item = readAIFunctionMeta(path);
99
- if (seen.has(item.functionKey)) {
100
- throw new Error(`Duplicate AI Function key: ${item.functionKey}`);
101
- }
102
- seen.add(item.functionKey);
103
- items.push(item);
104
- }
105
- if (items.length > MAX_AI_FUNCTIONS) {
106
- throw new Error(`AI Functions cannot exceed ${MAX_AI_FUNCTIONS}`);
107
- }
108
- return items;
174
+ return entry.isDirectory() && existsSync(path) && statSync(path).isFile();
175
+ })
176
+ .map((entry) => entry.name)
177
+ .sort();
109
178
  }
110
- // buildUpdatePayload 把本地全集转成 OpenAPIUpsertAIFunctions 的全量覆盖请求体。
111
- function buildUpdatePayload(items) {
112
- return JSON.stringify({
113
- ai_functions: items.map((item) => ({
114
- config_json: item.configJson,
115
- description: item.description,
116
- function_key: item.functionKey,
117
- name: item.name,
118
- })),
119
- });
179
+ // Full synchronization also validates each declared AI configuration.
180
+ export function collectLocalAIFunctions(workspace) {
181
+ return localAIFunctionKeys(workspace).map((key) => readAIFunctionMeta(join(aiFunctionsRoot(workspace), key, 'meta.json')));
120
182
  }
121
- // assertAIFunctionResultsOk 严格校验逐条结果:任一条 code != 0 立即抛错。
122
- // 后端整批拒绝时会同时返回顶层失败和 data.results;调用方必须保留逐条诊断,
123
- // 并阻止 deploy 继续上传产物或发布失败快照。
124
- function assertAIFunctionResultsOk(data) {
125
- const results = data.results ?? data.Results;
126
- if (results === undefined || results === null) {
127
- return;
128
- }
129
- if (!Array.isArray(results)) {
130
- throw new Error('AI Function sync returned an invalid results payload');
131
- }
132
- const failures = [];
133
- for (const entry of results) {
134
- if (!entry || typeof entry !== 'object')
135
- continue;
136
- const record = entry;
137
- const code = record.code ?? record.Code;
138
- if (typeof code === 'number' && code !== 0) {
139
- const key = record.function_key ?? record.functionKey ?? record.FunctionKey;
140
- const message = record.msg ?? record.Msg ?? record.message ?? '';
141
- failures.push(`${String(key ?? '(unknown)')}: code=${code}${message ? ` ${String(message)}` : ''}`);
142
- }
143
- }
144
- if (failures.length > 0) {
145
- throw new Error(`AI Function sync failed for ${failures.length} function(s): ${failures.join('; ')}`);
146
- }
183
+ export function aiFunctionWrite(item) {
184
+ return {
185
+ functionId: item.functionKey,
186
+ name: item.name,
187
+ description: item.description,
188
+ functionType: 'ai',
189
+ spec: item.configJson,
190
+ };
147
191
  }
148
- // syncAIFunctionsFullCover 走 OpenAPI 全量覆盖同步(对齐 update_functions 心智):传本地全集,服务端 diff 出
149
- // add/update/delete + 逐条校验码。deploy 与 `ai sync` 命令共用。空集合仍会清空远端 AI Function(全量覆盖语义)。
150
- // 任一条 results[].code != 0 立即抛错,避免 deploy 在 AI 同步失败后继续 artifact/publish。
151
192
  export function syncAIFunctionsFullCover(appToken, items, env, cwd) {
152
- const token = encodeURIComponent(appToken);
153
- let response;
154
193
  try {
155
- response = runLarkCli([
156
- 'api',
157
- 'POST',
158
- `/open-apis/base/v3/sites/${token}/ai_functions/update`,
159
- '--data',
160
- buildUpdatePayload(items),
161
- ], env, cwd);
194
+ return putFunctions(appToken, ['ai'], items.map(aiFunctionWrite), env, cwd);
162
195
  }
163
196
  catch (error) {
164
- // 顶层失败不能覆盖服务端保留的逐条诊断。
165
- if (error instanceof LarkCliError && error.details.results) {
166
- assertAIFunctionResultsOk({ results: error.details.results });
167
- }
168
197
  throw aiFunctionAccessError(error);
169
198
  }
170
- const data = responseData(response);
171
- assertAIFunctionResultsOk(data);
172
- return data;
173
199
  }
174
- function remoteAIFunctionKeys(appToken, env, cwd) {
175
- const data = responseData(runAIFunctionApi([
176
- 'api',
177
- 'GET',
178
- `/open-apis/base/v3/sites/${encodeURIComponent(appToken)}/ai_functions`,
179
- ], env, cwd));
180
- const list = Array.isArray(data.functions) ? data.functions : [];
181
- return list.flatMap((entry) => {
182
- if (!entry || typeof entry !== 'object')
183
- return [];
184
- const record = entry;
185
- const key = record.function_key ?? record.functionKey;
186
- return typeof key === 'string' && key !== '' ? [key] : [];
187
- });
200
+ // 专用管理接口返回完整草稿列表,不支持 Prod,也不要求 discovery 的 skillHash。
201
+ // 当前服务端不分页;如响应声明 hasMore,则必须读完游标,不能把首屏当全集。
202
+ function listDraftAIFunctions(appToken, env, cwd) {
203
+ const functions = [];
204
+ const keys = new Set();
205
+ const cursors = new Set();
206
+ let pageToken = '';
207
+ for (let page = 0; page < 1000; page++) {
208
+ const data = responseData(runAIFunctionApi([
209
+ 'api',
210
+ 'GET',
211
+ `/open-apis/base/v3/sites/${encodeURIComponent(appToken)}/ai_functions`,
212
+ ...(pageToken ? ['--params', JSON.stringify({ pageToken })] : []),
213
+ ], env, cwd));
214
+ const hasMore = data.hasMore ?? data.has_more;
215
+ if (!Array.isArray(data.functions) ||
216
+ (hasMore !== undefined && typeof hasMore !== 'boolean'))
217
+ throw new Error('AI_FUNCTION_RESPONSE_UNKNOWN: invalid AI Function list');
218
+ for (const item of data.functions) {
219
+ const key = item?.functionKey ?? item?.function_key;
220
+ if (typeof key !== 'string' ||
221
+ !/^[A-Za-z0-9_-]{1,64}$/.test(key) ||
222
+ keys.has(key))
223
+ throw new Error('AI_FUNCTION_RESPONSE_UNKNOWN: invalid or duplicate functionKey');
224
+ keys.add(key);
225
+ // 保持 1.4.1 的列表字段;专用接口缺失的发现元数据明确置空,不推断可调用性。
226
+ functions.push({
227
+ functionId: key,
228
+ name: item.name ?? null,
229
+ description: item.description ?? null,
230
+ functionType: 'ai',
231
+ capabilityType: item.capabilityType ?? item.capability_type ?? null,
232
+ mode: null,
233
+ result: null,
234
+ schemaStatus: null,
235
+ inputSchema: null,
236
+ agentTool: null,
237
+ statusReason: null,
238
+ statusHint: null,
239
+ });
240
+ }
241
+ if (!hasMore)
242
+ return functions;
243
+ const next = data.pageToken ?? data.page_token;
244
+ if (typeof next !== 'string' || !next || cursors.has(next))
245
+ throw new Error('AI Function list returned an empty or repeated pageToken');
246
+ cursors.add(next);
247
+ pageToken = next;
248
+ }
249
+ throw new Error('AI_FUNCTION_RESPONSE_UNKNOWN: unbounded AI Function list');
250
+ }
251
+ export function remoteAIFunctionKeys(appToken, env, cwd) {
252
+ return listDraftAIFunctions(appToken, env, cwd).map((item) => item.functionId);
253
+ }
254
+ function aiDetail(appToken, key, version, env, cwd) {
255
+ const view = getFunction(appToken, key, version, env, cwd);
256
+ if (view.functionType !== 'ai')
257
+ throw new Error(`Function ${key} is not an AI Function`);
258
+ return view;
259
+ }
260
+ function restoreAI(view, functionKey, workspace) {
261
+ if (!FUNCTION_ID_PATTERN.test(functionKey) || functionKey.length > 64)
262
+ throw new Error('Invalid remote AI Function key');
263
+ if (typeof view.name !== 'string' || typeof view.spec !== 'string')
264
+ throw new Error(`Remote AI Function ${functionKey} did not return name and spec`);
265
+ const parsed = parseAIJSON(view.spec);
266
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
267
+ throw new Error('AI spec must be an object');
268
+ const config = stripPlatformManagedFields(parsed);
269
+ const directory = join(aiFunctionsRoot(workspace), functionKey);
270
+ mkdirSync(directory, { recursive: true });
271
+ writeFileSync(join(directory, 'meta.json'), `${JSON.stringify({ name: view.name, description: view.description ?? '', config }, null, 2)}\n`);
188
272
  }
189
273
  // restoreRemoteAIFunctions 把远端 AI Function 草稿配置写回 <workspace>/ai/<key>/meta.json。
190
274
  // pull 调用它,让"修改已有应用前先恢复远端 AI Function"由 CLI 完成,而不是交给 Agent 判断。
191
- // 当前用户未开通 AI Function(800004011)时不算失败:本地不落 ai/,后续 deploy 自动跳过同步,远端保持原样。
275
+ // 仅明确的 feature-not-enabled 消息可分类跳过,普通权限错误必须失败。
192
276
  export function restoreRemoteAIFunctions(appToken, workspace, env, cwd) {
193
277
  let keys;
194
278
  try {
@@ -199,38 +283,8 @@ export function restoreRemoteAIFunctions(appToken, workspace, env, cwd) {
199
283
  return { status: 'not_enabled' };
200
284
  throw error;
201
285
  }
202
- const root = aiFunctionsRoot(workspace);
203
- for (const functionKey of keys) {
204
- if (functionKey.length > 64 || !FUNCTION_ID_PATTERN.test(functionKey)) {
205
- throw new Error(`Remote AI Function key is not restorable: ${functionKey}`);
206
- }
207
- const detail = responseData(runAIFunctionApi([
208
- 'api',
209
- 'GET',
210
- `/open-apis/base/v3/sites/${encodeURIComponent(appToken)}/ai_functions/${encodeURIComponent(functionKey)}`,
211
- ], env, cwd));
212
- const view = (detail.function ?? detail);
213
- const configJson = view.config_json ?? view.configJson;
214
- if (typeof view.name !== 'string' || typeof configJson !== 'string') {
215
- throw new Error(`Remote AI Function ${functionKey} did not return name and config_json`);
216
- }
217
- let config;
218
- try {
219
- config = JSON.parse(configJson);
220
- }
221
- catch {
222
- throw new Error(`Remote AI Function ${functionKey} config_json is not valid JSON`);
223
- }
224
- const directory = join(root, functionKey);
225
- mkdirSync(directory, { recursive: true });
226
- writeFileSync(join(directory, 'meta.json'), `${JSON.stringify({
227
- name: view.name,
228
- ...(typeof view.description === 'string' && view.description !== ''
229
- ? { description: view.description }
230
- : {}),
231
- config,
232
- }, null, 2)}\n`);
233
- }
286
+ const details = keys.map((key) => aiDetail(appToken, key, 'preview', env, cwd));
287
+ keys.forEach((key, index) => restoreAI(details[index], key, workspace));
234
288
  return { status: 'restored', functionKeys: keys };
235
289
  }
236
290
  // assertNoRemoteAIFunctionLoss 在全量覆盖前核对:远端已有的 key 必须都在本地全集中,否则拒绝,
@@ -262,127 +316,124 @@ export function syncAIFunctionsForDeploy(appToken, items, env, cwd) {
262
316
  assertNoRemoteAIFunctionLoss(appToken, items, env, cwd);
263
317
  return syncAIFunctionsFullCover(appToken, items, env, cwd);
264
318
  }
265
- async function resolveEnv(workspace, runtimeProfile) {
319
+ async function resolveEnv(workspace, runtimeProfile, explicitProfile) {
266
320
  const config = readConfig(workspace);
267
321
  assertProjectRuntimeProfile(config.runtimeProfile, runtimeProfile);
268
- const env = await runtimeProfile.commandEnvironment();
322
+ const { env } = resolveLarkProfileEnvironment(await runtimeProfile.commandEnvironment(), explicitProfile, config.larkProfile, runtimeProfile);
269
323
  return { config, env };
270
324
  }
271
325
  // listAIFunctions 列出 Site 下 AI Function。
272
326
  export async function listAIFunctions(options) {
273
327
  const workspace = resolve(options.directory);
274
328
  const runtimeProfile = options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE;
275
- const { config, env } = await resolveEnv(workspace, runtimeProfile);
276
- const response = runAIFunctionApi([
277
- 'api',
278
- 'GET',
279
- `/open-apis/base/v3/sites/${encodeURIComponent(config.appToken)}/ai_functions`,
280
- ], env, workspace);
281
- return responseData(response);
329
+ const { config, env } = await resolveEnv(workspace, runtimeProfile, options.larkProfile);
330
+ const version = functionEnv(options.env);
331
+ return {
332
+ env: version,
333
+ functions: version === 'preview'
334
+ ? listDraftAIFunctions(config.appToken, env, workspace)
335
+ : listFunctions(config.appToken, version, env, workspace).filter((item) => item.functionType === 'ai'),
336
+ };
282
337
  }
283
- // getAIFunction 读取单个 AI Function 配置(用于本地编辑 / diff)。
284
338
  export async function getAIFunction(functionKey, options) {
285
339
  const workspace = resolve(options.directory);
286
- const runtimeProfile = options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE;
287
- const { config, env } = await resolveEnv(workspace, runtimeProfile);
288
- const response = runAIFunctionApi([
289
- 'api',
290
- 'GET',
291
- `/open-apis/base/v3/sites/${encodeURIComponent(config.appToken)}/ai_functions/${encodeURIComponent(functionKey)}`,
292
- ], env, workspace);
293
- return responseData(response);
340
+ const { config, env } = await resolveEnv(workspace, options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE, options.larkProfile);
341
+ const version = functionEnv(options.env);
342
+ const view = aiDetail(config.appToken, functionKey, version, env, workspace);
343
+ if (version === 'prod')
344
+ return { env: version, function: view };
345
+ if (typeof view.spec !== 'string')
346
+ throw new Error('AI Function detail is missing spec');
347
+ return {
348
+ env: version,
349
+ function: view,
350
+ config: stripPlatformManagedFields(parseAIJSON(view.spec)),
351
+ };
352
+ }
353
+ export async function pullAIFunction(functionKey, options) {
354
+ if (functionEnv(options.env) !== 'preview')
355
+ throw new Error('AI pull requires env=preview');
356
+ const workspace = resolve(options.directory);
357
+ const { config, env } = await resolveEnv(workspace, options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE, options.larkProfile);
358
+ restoreAI(aiDetail(config.appToken, functionKey, 'preview', env, workspace), functionKey, workspace);
359
+ return { ok: true, functionKey, env: 'preview' };
294
360
  }
295
361
  // syncAIFunctions 把本地 ai/ 全集全量覆盖同步到 Site。
296
362
  export async function syncAIFunctions(options) {
297
363
  const workspace = resolve(options.directory);
298
364
  const runtimeProfile = options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE;
299
- const { config, env } = await resolveEnv(workspace, runtimeProfile);
365
+ const { config, env } = await resolveEnv(workspace, runtimeProfile, options.larkProfile);
300
366
  const items = collectLocalAIFunctions(workspace);
301
- const data = syncAIFunctionsFullCover(config.appToken, items, env, workspace);
367
+ const { deletedFunctionIds, ...data } = syncAIFunctionsFullCover(config.appToken, items, env, workspace);
302
368
  return {
303
369
  ok: true,
304
370
  appToken: config.appToken,
305
371
  count: items.length,
306
372
  results: data,
373
+ deletedFunctionIds,
307
374
  };
308
375
  }
309
376
  // validateAIFunction 静态校验单个本地 AI Function(保存/发布前,按能力分支),不落库。
310
377
  export async function validateAIFunction(functionKey, options) {
311
378
  const workspace = resolve(options.directory);
312
379
  const runtimeProfile = options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE;
313
- const { config, env } = await resolveEnv(workspace, runtimeProfile);
314
- const items = collectLocalAIFunctions(workspace);
315
- const target = items.find((item) => item.functionKey === functionKey);
316
- if (!target) {
380
+ const { config, env } = await resolveEnv(workspace, runtimeProfile, options.larkProfile);
381
+ if (!localAIFunctionKeys(workspace).includes(functionKey))
317
382
  throw new Error(`AI Function not found in ${AI_FUNCTIONS_DIR}/: ${functionKey}`);
318
- }
383
+ const target = readAIFunctionMeta(join(aiFunctionsRoot(workspace), functionKey, 'meta.json'));
319
384
  const response = runAIFunctionApi([
320
385
  'api',
321
386
  'POST',
322
- `/open-apis/base/v3/sites/${encodeURIComponent(config.appToken)}/ai_functions/validate`,
387
+ `/open-apis/base/v3/sites/${encodeURIComponent(config.appToken)}/functions/validate`,
323
388
  '--data',
324
- JSON.stringify({
325
- function: {
326
- config_json: target.configJson,
327
- description: target.description,
328
- function_key: target.functionKey,
329
- name: target.name,
330
- },
331
- }),
389
+ JSON.stringify({ kinds: ['ai'], functions: [aiFunctionWrite(target)] }),
332
390
  ], env, workspace);
333
391
  const data = responseData(response);
334
- if (data.is_success !== true) {
335
- const message = String(data.err_msg ?? 'unknown validation error');
336
- throw new Error(`AI Function validation failed: ${message}`);
337
- }
338
- return data;
339
- }
340
- function readCapabilityType(data) {
341
- const value = data.function;
342
- if (!value || typeof value !== 'object') {
343
- throw new Error('AI Function detail does not contain function');
344
- }
345
- const view = value;
346
- const raw = view.config_json;
347
- if (typeof raw !== 'string' || raw === '') {
348
- throw new Error('AI Function detail is missing config_json');
349
- }
350
- let parsed;
351
- try {
352
- parsed = JSON.parse(raw);
353
- }
354
- catch {
355
- throw new Error('AI Function detail config_json is not valid JSON');
356
- }
357
- if (!parsed || typeof parsed !== 'object') {
358
- throw new Error('AI Function detail config_json is not an object');
359
- }
360
- const capability = parsed.capability_type;
361
- if (typeof capability !== 'string' || !CAPABILITY_TYPES.has(capability)) {
362
- throw new Error('AI Function detail contains invalid capability_type');
363
- }
364
- return capability;
392
+ assertFunctionResults(data, [functionKey]);
393
+ if (data.valid !== true)
394
+ throw new Error('AI Function validation failed');
395
+ const hints = responseFunctionHints(data, [functionKey]);
396
+ return {
397
+ ...data,
398
+ ...(hints.length
399
+ ? {
400
+ functionHints: hints,
401
+ functionHintsGuide: `Review hints against ${AGENT_TOOL_DESIGN_REFERENCE}.`,
402
+ }
403
+ : {}),
404
+ };
365
405
  }
366
- // debugAIFunction 调试 text/vision 时走 unary 聚合;image/video 走统一 tasks 提交接口。
367
406
  export async function debugAIFunction(functionKey, options) {
368
407
  const workspace = resolve(options.directory);
369
408
  const runtimeProfile = options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE;
370
- const { config, env } = await resolveEnv(workspace, runtimeProfile);
409
+ const { config, env } = await resolveEnv(workspace, runtimeProfile, options.larkProfile);
371
410
  const token = encodeURIComponent(config.appToken);
372
411
  const key = encodeURIComponent(functionKey);
373
- const detail = runAIFunctionApi(['api', 'GET', `/open-apis/base/v3/sites/${token}/ai_functions/${key}`], env, workspace);
374
- const capabilityType = readCapabilityType(responseData(detail));
375
- const body = JSON.stringify({
376
- input: options.input ?? {},
377
- messages: options.messages ?? [],
378
- variables: options.variables ?? {},
379
- });
412
+ const version = functionEnv(options.env);
413
+ if (options.params !== undefined && options.variables !== undefined)
414
+ throw new Error('--params and --variables are mutually exclusive');
415
+ if (options.variables !== undefined)
416
+ process.stderr.write('Warning: --variables 已弃用,请使用 --params。\n');
417
+ const params = options.params ?? options.variables ?? {};
418
+ if (!params || typeof params !== 'object' || Array.isArray(params))
419
+ throw new Error('--params must be a JSON object');
420
+ const detail = aiDetail(config.appToken, functionKey, version, env, workspace);
421
+ const capabilityType = detail.capabilityType;
422
+ if (typeof capabilityType !== 'string' ||
423
+ !CAPABILITY_TYPES.has(capabilityType))
424
+ throw new Error('AI Function detail contains invalid capabilityType');
425
+ const media = capabilityType === 'image' || capabilityType === 'video';
426
+ if (media ? options.messages !== undefined : options.input !== undefined)
427
+ throw new Error('AI capability does not accept the supplied messages/input');
428
+ const body = JSON.stringify(media
429
+ ? { params, input: options.input ?? {} }
430
+ : { params, messages: options.messages ?? [] });
380
431
  const response = runAIFunctionApi([
381
432
  'api',
382
433
  'POST',
383
- `/open-apis/base/v3/sites/${token}/ai_functions/${key}/${capabilityType === 'image' || capabilityType === 'video' ? 'tasks' : 'invoke'}`,
434
+ `/open-apis/base/v3/sites/${token}/functions/${key}/invoke`,
384
435
  '--params',
385
- JSON.stringify({ env: options.env }),
436
+ JSON.stringify({ env: functionEnv(options.env), includeInternal: true }),
386
437
  '--data',
387
438
  body,
388
439
  ], env, workspace);
@@ -392,16 +443,17 @@ export async function debugAIFunction(functionKey, options) {
392
443
  export async function getAIFunctionTask(functionKey, taskId, options) {
393
444
  const workspace = resolve(options.directory);
394
445
  const runtimeProfile = options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE;
395
- const { config, env } = await resolveEnv(workspace, runtimeProfile);
446
+ const { config, env } = await resolveEnv(workspace, runtimeProfile, options.larkProfile);
396
447
  const token = encodeURIComponent(config.appToken);
397
448
  const key = encodeURIComponent(functionKey);
398
449
  const task = encodeURIComponent(taskId);
450
+ process.stderr.write(`AI task env=${functionEnv(options.env)};查询成功不等于生成成功,请按 status 判断。\n`);
399
451
  const response = runAIFunctionApi([
400
452
  'api',
401
453
  'GET',
402
- `/open-apis/base/v3/sites/${token}/ai_functions/${key}/tasks/${task}`,
454
+ `/open-apis/base/v3/sites/${token}/functions/${key}/tasks/${task}`,
403
455
  '--params',
404
- JSON.stringify({ env: options.env }),
456
+ JSON.stringify({ env: functionEnv(options.env), includeInternal: true }),
405
457
  ], env, workspace);
406
458
  return responseData(response);
407
459
  }
@@ -409,7 +461,7 @@ export async function getAIFunctionTask(functionKey, taskId, options) {
409
461
  export async function getAIFunctionUsage(options) {
410
462
  const workspace = resolve(options.directory);
411
463
  const runtimeProfile = options.runtimeProfile ?? ONLINE_RUNTIME_PROFILE;
412
- const { config, env } = await resolveEnv(workspace, runtimeProfile);
464
+ const { config, env } = await resolveEnv(workspace, runtimeProfile, options.larkProfile);
413
465
  const token = encodeURIComponent(config.appToken);
414
466
  const params = {};
415
467
  if (options.from !== undefined)