@nocobase/plugin-ai 2.2.0-alpha.5 → 2.2.0-alpha.7

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 (50) hide show
  1. package/dist/ai/docs/nocobase/file-manager/storage/local.md +3 -1
  2. package/dist/ai/docs/nocobase/get-started/installation/docker-caddy.mdx +6 -1
  3. package/dist/ai/docs/nocobase/get-started/installation/docker-nginx.mdx +6 -2
  4. package/dist/ai/docs/nocobase/get-started/installation/docker.mdx +94 -1
  5. package/dist/ai/docs/nocobase/security/guide.md +23 -0
  6. package/dist/ai/tools/subAgentWebSearch.js +20 -15
  7. package/dist/client/index.js +1 -1
  8. package/dist/client-v2/ai-employees/tools/data-modeling/useFieldInterfaceOptions.d.ts +1 -0
  9. package/dist/client-v2/index.js +1 -1
  10. package/dist/client-v2/llm-providers/forms.d.ts +2 -0
  11. package/dist/client-v2/llm-providers/index.d.ts +1 -0
  12. package/dist/externalVersion.js +15 -15
  13. package/dist/locale/en-US.json +5 -0
  14. package/dist/locale/zh-CN.json +5 -0
  15. package/dist/node_modules/@langchain/mistralai/package.json +1 -1
  16. package/dist/node_modules/@langchain/xai/package.json +1 -1
  17. package/dist/node_modules/fs-extra/package.json +1 -1
  18. package/dist/node_modules/jsonrepair/package.json +1 -1
  19. package/dist/node_modules/just-bash/package.json +1 -1
  20. package/dist/node_modules/nodejs-snowflake/package.json +1 -1
  21. package/dist/node_modules/openai/package.json +1 -1
  22. package/dist/node_modules/zod/package.json +1 -1
  23. package/dist/server/ai-employees/ai-employee.js +2 -1
  24. package/dist/server/ai-employees/prompts.d.ts +2 -1
  25. package/dist/server/ai-employees/prompts.js +8 -2
  26. package/dist/server/collections/ai-usage-events.d.ts +10 -0
  27. package/dist/server/collections/ai-usage-events.js +183 -0
  28. package/dist/server/llm-providers/dashscope.d.ts +2 -1
  29. package/dist/server/llm-providers/dashscope.js +16 -1
  30. package/dist/server/llm-providers/deepseek.d.ts +2 -1
  31. package/dist/server/llm-providers/deepseek.js +33 -2
  32. package/dist/server/llm-providers/kimi/provider.d.ts +2 -1
  33. package/dist/server/llm-providers/kimi/provider.js +22 -2
  34. package/dist/server/llm-providers/mistral.d.ts +36 -2
  35. package/dist/server/llm-providers/mistral.js +62 -2
  36. package/dist/server/llm-providers/openai/completions.d.ts +2 -1
  37. package/dist/server/llm-providers/openai/completions.js +17 -1
  38. package/dist/server/llm-providers/openai/responses.d.ts +2 -1
  39. package/dist/server/llm-providers/openai/responses.js +17 -1
  40. package/dist/server/llm-providers/orcarouter.d.ts +35 -0
  41. package/dist/server/llm-providers/orcarouter.js +155 -0
  42. package/dist/server/llm-providers/provider.d.ts +7 -0
  43. package/dist/server/llm-providers/provider.js +7 -1
  44. package/dist/server/manager/ai-chat-conversation.js +2 -0
  45. package/dist/server/manager/ai-manager.d.ts +2 -1
  46. package/dist/server/manager/ai-manager.js +4 -1
  47. package/dist/server/manager/ai-usage-events.d.ts +49 -0
  48. package/dist/server/manager/ai-usage-events.js +195 -0
  49. package/dist/server/plugin.js +2 -0
  50. package/package.json +2 -2
@@ -40,6 +40,7 @@ __export(ai_chat_conversation_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(ai_chat_conversation_exports);
42
42
  var import_lodash = __toESM(require("lodash"));
43
+ var import_ai_usage_events = require("./ai-usage-events");
43
44
  const createAIChatConversation = (ctx, sessionId) => {
44
45
  return new AIChatConversationImpl(ctx, sessionId);
45
46
  };
@@ -81,6 +82,7 @@ class AIChatConversationImpl {
81
82
  ),
82
83
  transaction: this.transaction
83
84
  });
85
+ await (0, import_ai_usage_events.recordAIUsageEventsForMessages)(this.ctx, this.sessionId, instances, this.transaction);
84
86
  return isArray ? instances : instances[0];
85
87
  }
86
88
  async removeMessages({ messageId }) {
@@ -6,7 +6,7 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
- import { LLMProvider, LLMProviderOptions, EmbeddingProvider, EmbeddingProviderOptions } from '../llm-providers/provider';
9
+ import { LLMProvider, LLMProviderOptions, EmbeddingProvider, EmbeddingProviderOptions, ReasoningOptions } from '../llm-providers/provider';
10
10
  import PluginAIServer from '../plugin';
11
11
  import { ToolManager } from './tool-manager';
12
12
  export type LLMProviderMeta = {
@@ -25,6 +25,7 @@ export type LLMModelOptions = {
25
25
  llmService: string;
26
26
  model: string;
27
27
  webSearch?: boolean;
28
+ reasoning?: ReasoningOptions;
28
29
  };
29
30
  export type EnabledLLMModel = {
30
31
  label: string;
@@ -123,7 +123,7 @@ class AIManager {
123
123
  return (0, import_recommended_models.getRecommendedModels)(provider);
124
124
  }
125
125
  async getLLMService(options) {
126
- const { llmService, model, webSearch } = options ?? {};
126
+ const { llmService, model, webSearch, reasoning } = options ?? {};
127
127
  if (!llmService || !model) {
128
128
  throw new Error("LLM service not configured");
129
129
  }
@@ -134,6 +134,9 @@ class AIManager {
134
134
  if (webSearch === true) {
135
135
  modelOptions.builtIn = { webSearch: true };
136
136
  }
137
+ if (reasoning) {
138
+ modelOptions._reasoning = reasoning;
139
+ }
137
140
  const service = await this.plugin.db.getRepository("llmServices").findOne({
138
141
  filter: {
139
142
  name: llmService
@@ -0,0 +1,49 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import { Context } from '@nocobase/actions';
10
+ import { Transaction } from '@nocobase/database';
11
+ import { AIMessage } from '../types';
12
+ type RecordLike = Record<string, unknown> & {
13
+ get?: (key: string) => unknown;
14
+ };
15
+ export type NormalizedUsageMetadata = {
16
+ inputTokens: number;
17
+ outputTokens: number;
18
+ totalTokens: number;
19
+ cachedTokens: number;
20
+ reasoningTokens: number;
21
+ };
22
+ export type AIUsageEventValues = {
23
+ occurredAt: Date;
24
+ sessionId: string;
25
+ messageId: string;
26
+ userId?: unknown;
27
+ aiEmployeeUsername?: unknown;
28
+ from: string;
29
+ category: string;
30
+ eventType: 'llm_message';
31
+ role: string;
32
+ provider: string;
33
+ llmService?: string;
34
+ model: string;
35
+ inputTokens: number;
36
+ outputTokens: number;
37
+ totalTokens: number;
38
+ cachedTokens: number;
39
+ reasoningTokens: number;
40
+ toolCallCount: number;
41
+ autoToolCallCount: number;
42
+ status: 'success';
43
+ rawUsageMetadata: Record<string, unknown>;
44
+ rawResponseMetadata?: Record<string, unknown>;
45
+ };
46
+ export declare function normalizeUsageMetadata(usageMetadata: Record<string, unknown>): NormalizedUsageMetadata;
47
+ export declare function buildAIUsageEventValues(sessionId: string, message: AIMessage, conversation: RecordLike): AIUsageEventValues | null;
48
+ export declare function recordAIUsageEventsForMessages(ctx: Context, sessionId: string, messages: AIMessage[], transaction?: Transaction): Promise<void>;
49
+ export {};
@@ -0,0 +1,195 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var ai_usage_events_exports = {};
28
+ __export(ai_usage_events_exports, {
29
+ buildAIUsageEventValues: () => buildAIUsageEventValues,
30
+ normalizeUsageMetadata: () => normalizeUsageMetadata,
31
+ recordAIUsageEventsForMessages: () => recordAIUsageEventsForMessages
32
+ });
33
+ module.exports = __toCommonJS(ai_usage_events_exports);
34
+ const SKIPPED_MESSAGE_ROLES = /* @__PURE__ */ new Set(["user", "tool", "system"]);
35
+ function normalizeUsageMetadata(usageMetadata) {
36
+ const inputTokens = getNumericValue(usageMetadata, ["input_tokens", "prompt_tokens", "inputTokens", "promptTokens"]) ?? 0;
37
+ const outputTokens = getNumericValue(usageMetadata, ["output_tokens", "completion_tokens", "outputTokens", "completionTokens"]) ?? 0;
38
+ const totalTokens = getNumericValue(usageMetadata, ["total_tokens", "totalTokens"]) ?? inputTokens + outputTokens;
39
+ const cachedTokens = getNumericValue(usageMetadata, ["cached_tokens", "cachedTokens"]) ?? getNestedNumericValue(usageMetadata, ["input_token_details", "cache_read"]) ?? getNestedNumericValue(usageMetadata, ["input_token_details", "cached_tokens"]) ?? getNestedNumericValue(usageMetadata, ["prompt_tokens_details", "cached_tokens"]) ?? 0;
40
+ const reasoningTokens = getNumericValue(usageMetadata, ["reasoning_tokens", "reasoningTokens"]) ?? getNestedNumericValue(usageMetadata, ["output_token_details", "reasoning"]) ?? getNestedNumericValue(usageMetadata, ["completion_tokens_details", "reasoning_tokens"]) ?? 0;
41
+ return {
42
+ inputTokens,
43
+ outputTokens,
44
+ totalTokens,
45
+ cachedTokens,
46
+ reasoningTokens
47
+ };
48
+ }
49
+ function buildAIUsageEventValues(sessionId, message, conversation) {
50
+ const role = readString(message, "role");
51
+ if (!role || SKIPPED_MESSAGE_ROLES.has(role)) {
52
+ return null;
53
+ }
54
+ const metadata = readRecord(message, "metadata");
55
+ const provider = readString(metadata, "provider");
56
+ const model = readString(metadata, "model");
57
+ if (!provider || !model) {
58
+ return null;
59
+ }
60
+ const usageMetadata = readRecord(metadata, "usage_metadata") ?? {};
61
+ const responseMetadata = readRecord(metadata, "response_metadata");
62
+ const normalizedUsage = normalizeUsageMetadata(usageMetadata);
63
+ const toolCalls = readArray(message, "toolCalls");
64
+ const autoCallTools = readArray(metadata, "autoCallTools");
65
+ const llmService = readString(metadata, "llmService");
66
+ return {
67
+ occurredAt: normalizeDate(readValue(message, "createdAt")),
68
+ sessionId,
69
+ messageId: String(readValue(message, "messageId") ?? ""),
70
+ userId: readValue(conversation, "userId"),
71
+ aiEmployeeUsername: readValue(conversation, "aiEmployeeUsername"),
72
+ from: readString(conversation, "from") ?? "main-agent",
73
+ category: readString(conversation, "category") ?? "chat",
74
+ eventType: "llm_message",
75
+ role,
76
+ provider,
77
+ ...llmService ? { llmService } : {},
78
+ model,
79
+ ...normalizedUsage,
80
+ toolCallCount: (toolCalls == null ? void 0 : toolCalls.length) ?? 0,
81
+ autoToolCallCount: (autoCallTools == null ? void 0 : autoCallTools.length) ?? 0,
82
+ status: "success",
83
+ rawUsageMetadata: usageMetadata,
84
+ ...responseMetadata ? { rawResponseMetadata: responseMetadata } : {}
85
+ };
86
+ }
87
+ async function recordAIUsageEventsForMessages(ctx, sessionId, messages, transaction) {
88
+ const recordableMessages = messages.filter(isRecordableLLMMessage);
89
+ if (recordableMessages.length === 0) {
90
+ return;
91
+ }
92
+ const conversation = await ctx.db.getRepository("aiConversations").findOne({
93
+ filter: {
94
+ sessionId
95
+ },
96
+ transaction
97
+ });
98
+ if (!conversation) {
99
+ return;
100
+ }
101
+ const usageEvents = recordableMessages.map((message) => buildAIUsageEventValues(sessionId, message, conversation)).filter(isUsageEventValues);
102
+ if (usageEvents.length === 0) {
103
+ return;
104
+ }
105
+ const usageEventsRepo = ctx.db.getRepository("aiUsageEvents");
106
+ for (const values of usageEvents) {
107
+ await usageEventsRepo.updateOrCreate({
108
+ filterKeys: ["messageId", "eventType"],
109
+ values,
110
+ transaction
111
+ });
112
+ }
113
+ }
114
+ function isUsageEventValues(value) {
115
+ return value !== null && value.messageId !== "";
116
+ }
117
+ function isRecordableLLMMessage(message) {
118
+ const role = readString(message, "role");
119
+ if (!role || SKIPPED_MESSAGE_ROLES.has(role)) {
120
+ return false;
121
+ }
122
+ const metadata = readRecord(message, "metadata");
123
+ return Boolean(readString(metadata, "provider") && readString(metadata, "model"));
124
+ }
125
+ function isRecord(value) {
126
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
127
+ }
128
+ function readValue(source, key) {
129
+ if (!isRecord(source)) {
130
+ return void 0;
131
+ }
132
+ const value = source[key];
133
+ if (value !== void 0) {
134
+ return value;
135
+ }
136
+ if (typeof source.get === "function") {
137
+ return source.get(key);
138
+ }
139
+ return void 0;
140
+ }
141
+ function readString(source, key) {
142
+ const value = readValue(source, key);
143
+ return typeof value === "string" && value !== "" ? value : void 0;
144
+ }
145
+ function readRecord(source, key) {
146
+ const value = readValue(source, key);
147
+ return isRecord(value) ? value : void 0;
148
+ }
149
+ function readArray(source, key) {
150
+ const value = readValue(source, key);
151
+ return Array.isArray(value) ? value : void 0;
152
+ }
153
+ function getNumericValue(source, keys) {
154
+ for (const key of keys) {
155
+ const normalized = normalizeNumber(source[key]);
156
+ if (normalized !== void 0) {
157
+ return normalized;
158
+ }
159
+ }
160
+ }
161
+ function getNestedNumericValue(source, path) {
162
+ let current = source;
163
+ for (const key of path) {
164
+ if (!isRecord(current)) {
165
+ return void 0;
166
+ }
167
+ current = current[key];
168
+ }
169
+ return normalizeNumber(current);
170
+ }
171
+ function normalizeNumber(value) {
172
+ const numeric = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
173
+ if (!Number.isFinite(numeric)) {
174
+ return void 0;
175
+ }
176
+ return Math.max(0, Math.trunc(numeric));
177
+ }
178
+ function normalizeDate(value) {
179
+ if (value instanceof Date && Number.isFinite(value.getTime())) {
180
+ return value;
181
+ }
182
+ if (typeof value === "string" || typeof value === "number") {
183
+ const date = new Date(value);
184
+ if (Number.isFinite(date.getTime())) {
185
+ return date;
186
+ }
187
+ }
188
+ return /* @__PURE__ */ new Date();
189
+ }
190
+ // Annotate the CommonJS export names for ESM import in node:
191
+ 0 && (module.exports = {
192
+ buildAIUsageEventValues,
193
+ normalizeUsageMetadata,
194
+ recordAIUsageEventsForMessages
195
+ });
@@ -75,6 +75,7 @@ var import_document_loader = require("./document-loader");
75
75
  var import_checkpoints = require("./ai-employees/checkpoints");
76
76
  var import_mimo = require("./llm-providers/mimo");
77
77
  var import_mistral = require("./llm-providers/mistral");
78
+ var import_orcarouter = require("./llm-providers/orcarouter");
78
79
  var import_sub_agents = require("./ai-employees/sub-agents");
79
80
  var import_employee = require("./workflow/nodes/employee");
80
81
  var import_ai_knowledge_base = require("./ai-employees/ai-knowledge-base");
@@ -186,6 +187,7 @@ class PluginAIServer extends import_server.Plugin {
186
187
  this.aiManager.registerLLMProvider("openai-completions", import_openai2.openaiCompletionsProviderOptions);
187
188
  this.aiManager.registerLLMProvider("kimi", import_kimi.kimiProviderOptions);
188
189
  this.aiManager.registerLLMProvider("xai", import_xai.xaiProviderOptions);
190
+ this.aiManager.registerLLMProvider("orcarouter", import_orcarouter.orcarouterProviderOptions);
189
191
  }
190
192
  registerTools() {
191
193
  const toolsManager = this.ai.toolsManager;
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description": "Create AI employees with diverse skills to collaborate with humans, build systems, and handle business operations.",
7
7
  "description.ru-RU": "Поддержка интеграции с AI-сервисами: предоставляются AI-узлы для рабочих процессов, расширяя возможности бизнес-обработки.",
8
8
  "description.zh-CN": "创建各种技能的 AI 员工,与人类协同,搭建系统,处理业务。",
9
- "version": "2.2.0-alpha.5",
9
+ "version": "2.2.0-alpha.7",
10
10
  "main": "dist/server/index.js",
11
11
  "homepage": "https://docs.nocobase.com/handbook/action-ai",
12
12
  "homepage.ru-RU": "https://docs-ru.nocobase.com/handbook/action-ai",
@@ -66,5 +66,5 @@
66
66
  "keywords": [
67
67
  "AI"
68
68
  ],
69
- "gitHead": "814ff497dd1233ca7218c9f7f2a016c2ead6516d"
69
+ "gitHead": "34ba02960fca9ab0b6881d3db7040a8a64067bba"
70
70
  }