@nebutra/agents 1.0.0 → 1.1.1

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 (39) hide show
  1. package/.turbo/turbo-build.log +40 -0
  2. package/.turbo/turbo-test.log +19 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/CHANGELOG.md +36 -0
  5. package/dist/agent-CahnMASx.d.ts +32 -0
  6. package/dist/chunk-5JZJ5KMC.js +37 -0
  7. package/dist/chunk-5LX742GP.js +224 -0
  8. package/dist/chunk-B7XWL35G.js +60 -0
  9. package/dist/chunk-NPQECBXL.js +82 -0
  10. package/dist/chunk-NVPE5EDI.js +42 -0
  11. package/dist/chunk-RDOFKRI6.js +166 -0
  12. package/dist/chunk-RLWM437Q.js +61 -0
  13. package/dist/chunk-UVL2UVVM.js +56 -0
  14. package/dist/index.d.ts +476 -0
  15. package/dist/index.js +533 -0
  16. package/dist/providers/langchain.d.ts +18 -0
  17. package/dist/providers/langchain.js +23 -0
  18. package/dist/providers/vercel-ai.d.ts +16 -0
  19. package/dist/providers/vercel-ai.js +83 -0
  20. package/dist/sdk/config.d.ts +48 -0
  21. package/dist/sdk/config.js +10 -0
  22. package/dist/sdk/index.d.ts +94 -0
  23. package/dist/sdk/index.js +33 -0
  24. package/dist/sdk/models.d.ts +40 -0
  25. package/dist/sdk/models.js +8 -0
  26. package/dist/sdk/provider.d.ts +21 -0
  27. package/dist/sdk/provider.js +10 -0
  28. package/dist/tools.d.ts +20 -0
  29. package/dist/tools.js +12 -0
  30. package/dist/types-NtgB3pch.d.ts +92 -0
  31. package/package.json +8 -13
  32. package/src/__tests__/cost-observability.test.ts +1 -1
  33. package/src/__tests__/generation.test.ts +111 -0
  34. package/src/__tests__/runtime-gateway.test.ts +108 -0
  35. package/src/gateway.ts +234 -0
  36. package/src/generation/index.ts +157 -0
  37. package/src/generation/mock-provider.ts +123 -0
  38. package/src/generation/types.ts +87 -0
  39. package/src/index.ts +18 -0
@@ -0,0 +1,166 @@
1
+ // src/memory.ts
2
+ import { logger } from "@nebutra/logger";
3
+ var DEFAULT_TTL_SECONDS = 7 * 24 * 60 * 60;
4
+ function getTtl() {
5
+ const envTtl = process.env.AGENT_MEMORY_TTL_SECONDS;
6
+ if (envTtl) {
7
+ const parsed = Number.parseInt(envTtl, 10);
8
+ if (!Number.isNaN(parsed) && parsed > 0) {
9
+ return parsed;
10
+ }
11
+ }
12
+ return DEFAULT_TTL_SECONDS;
13
+ }
14
+ function memoryKey(tenantId, conversationId) {
15
+ return `agent:memory:${tenantId}:${conversationId}`;
16
+ }
17
+ async function tryGetRedis() {
18
+ try {
19
+ const { getRedis } = await import("@nebutra/cache");
20
+ return getRedis();
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+ async function getMemory(tenantId, conversationId) {
26
+ const redis = await tryGetRedis();
27
+ if (!redis) return [];
28
+ try {
29
+ const raw = await redis.get(memoryKey(tenantId, conversationId));
30
+ if (!raw) return [];
31
+ const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
32
+ if (!Array.isArray(parsed)) return [];
33
+ return parsed.map((m) => {
34
+ const toolCalls = m.toolCalls;
35
+ if (Array.isArray(toolCalls) && toolCalls.length > 0) {
36
+ return {
37
+ role: m.role,
38
+ content: String(m.content ?? ""),
39
+ toolCalls,
40
+ timestamp: new Date(String(m.timestamp))
41
+ };
42
+ }
43
+ return {
44
+ role: m.role,
45
+ content: String(m.content ?? ""),
46
+ timestamp: new Date(String(m.timestamp))
47
+ };
48
+ });
49
+ } catch (error) {
50
+ logger.warn("Failed to load agent memory, falling back to empty", {
51
+ tenantId,
52
+ conversationId,
53
+ error
54
+ });
55
+ return [];
56
+ }
57
+ }
58
+ async function saveMemory(tenantId, conversationId, messages) {
59
+ const redis = await tryGetRedis();
60
+ if (!redis) return;
61
+ try {
62
+ const key = memoryKey(tenantId, conversationId);
63
+ await redis.set(key, JSON.stringify(messages), { ex: getTtl() });
64
+ } catch (error) {
65
+ logger.warn("Failed to save agent memory", {
66
+ tenantId,
67
+ conversationId,
68
+ error
69
+ });
70
+ }
71
+ }
72
+ async function clearMemory(tenantId, conversationId) {
73
+ const redis = await tryGetRedis();
74
+ if (!redis) return;
75
+ try {
76
+ await redis.del(memoryKey(tenantId, conversationId));
77
+ } catch (error) {
78
+ logger.warn("Failed to clear agent memory", {
79
+ tenantId,
80
+ conversationId,
81
+ error
82
+ });
83
+ }
84
+ }
85
+
86
+ // src/agent.ts
87
+ import { logger as logger2 } from "@nebutra/logger";
88
+ var BaseAgent = class {
89
+ config;
90
+ constructor(config) {
91
+ this.config = config;
92
+ }
93
+ /**
94
+ * Run the agent with full lifecycle:
95
+ * 1. Load long-term memory (if configured)
96
+ * 2. Trim to short-term window
97
+ * 3. Delegate to provider-specific `execute()`
98
+ * 4. Track usage for billing
99
+ * 5. Persist new messages to memory
100
+ */
101
+ async run(messages, context) {
102
+ const startTime = Date.now();
103
+ const memory = this.config.memory?.longTerm?.enabled ? await getMemory(context.tenantId, context.conversationId) : [];
104
+ const maxMessages = this.config.memory?.shortTerm?.maxMessages ?? 50;
105
+ const allMessages = [...memory, ...messages].slice(-maxMessages);
106
+ const response = await this.execute(allMessages, context);
107
+ const durationMs = Date.now() - startTime;
108
+ const usage = {
109
+ tenantId: context.tenantId,
110
+ userId: context.userId,
111
+ agentId: this.config.id,
112
+ model: this.config.model,
113
+ promptTokens: response.usage.promptTokens,
114
+ completionTokens: response.usage.completionTokens,
115
+ totalTokens: response.usage.totalTokens,
116
+ durationMs,
117
+ timestamp: /* @__PURE__ */ new Date()
118
+ };
119
+ logger2.info("Agent execution completed", {
120
+ agentId: this.config.id,
121
+ tenantId: context.tenantId,
122
+ tokens: usage.totalTokens,
123
+ durationMs
124
+ });
125
+ if (this.config.memory?.longTerm?.enabled) {
126
+ await saveMemory(context.tenantId, context.conversationId, response.messages);
127
+ }
128
+ await this.emitUsage(usage);
129
+ return response;
130
+ }
131
+ /**
132
+ * Provider-specific execution. Subclasses MUST override this.
133
+ */
134
+ async execute(_messages, _context) {
135
+ throw new Error("execute() must be implemented by provider adapter");
136
+ }
137
+ /**
138
+ * Emit a usage event for downstream billing / metering.
139
+ */
140
+ async emitUsage(event) {
141
+ try {
142
+ const { deductCredits } = await import("@nebutra/billing/credits");
143
+ const totalTokens = event.totalTokens || 0;
144
+ if (totalTokens === 0) return;
145
+ const creditCost = Math.max(1, Math.ceil(totalTokens / 1e4));
146
+ await deductCredits({
147
+ organizationId: event.tenantId,
148
+ amount: creditCost,
149
+ description: `Agent execution: ${event.model}`
150
+ });
151
+ } catch (err) {
152
+ logger2.error("Failed to emit usage or deduct credits for agent execution", {
153
+ tenantId: event.tenantId,
154
+ agentId: event.agentId,
155
+ error: err
156
+ });
157
+ }
158
+ }
159
+ };
160
+
161
+ export {
162
+ getMemory,
163
+ saveMemory,
164
+ clearMemory,
165
+ BaseAgent
166
+ };
@@ -0,0 +1,61 @@
1
+ import {
2
+ resolveApiKey
3
+ } from "./chunk-NVPE5EDI.js";
4
+ import {
5
+ resolveModel
6
+ } from "./chunk-5JZJ5KMC.js";
7
+
8
+ // src/sdk/provider.ts
9
+ import { createOpenAI } from "@ai-sdk/openai";
10
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
11
+ function createModel(modelOrPreset, config) {
12
+ const modelId = resolveModel(modelOrPreset);
13
+ const apiKey = resolveApiKey(config);
14
+ switch (config.provider) {
15
+ case "openrouter": {
16
+ const provider = createOpenRouter({
17
+ apiKey,
18
+ ...config.headers ? { headers: config.headers } : {},
19
+ ...config.extraBody ? { extraBody: config.extraBody } : {}
20
+ });
21
+ return provider.chat(modelId);
22
+ }
23
+ case "openai": {
24
+ const provider = createOpenAI({ apiKey });
25
+ return provider(modelId);
26
+ }
27
+ case "siliconflow": {
28
+ const provider = createOpenAI({
29
+ apiKey,
30
+ baseURL: "https://api.siliconflow.cn/v1"
31
+ });
32
+ return provider(modelId);
33
+ }
34
+ case "gateway": {
35
+ const provider = createOpenAI({
36
+ apiKey,
37
+ baseURL: "https://ai-gateway.vercel.sh/v1"
38
+ });
39
+ return provider(modelId);
40
+ }
41
+ }
42
+ }
43
+ function createEmbeddingModel(modelOrPreset, config) {
44
+ const modelId = resolveModel(modelOrPreset);
45
+ const apiKey = resolveApiKey(config);
46
+ if (config.provider !== "openrouter") {
47
+ throw new Error(
48
+ `[@nebutra/agents] Embedding models are currently only supported with the "openrouter" provider.`
49
+ );
50
+ }
51
+ const provider = createOpenRouter({
52
+ apiKey,
53
+ ...config.headers ? { headers: config.headers } : {}
54
+ });
55
+ return provider.textEmbeddingModel(modelId);
56
+ }
57
+
58
+ export {
59
+ createModel,
60
+ createEmbeddingModel
61
+ };
@@ -0,0 +1,56 @@
1
+ // src/tools.ts
2
+ var webSearchTool = {
3
+ name: "web_search",
4
+ description: "Search the web for current information",
5
+ inputSchema: {
6
+ type: "object",
7
+ properties: { query: { type: "string" } },
8
+ required: ["query"]
9
+ },
10
+ execute: async (_input, _context) => {
11
+ return {
12
+ results: [],
13
+ note: "Configure TAVILY_API_KEY or SERPER_API_KEY for live search"
14
+ };
15
+ }
16
+ };
17
+ var databaseQueryTool = {
18
+ name: "database_query",
19
+ description: "Query the tenant's database",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: { query: { type: "string" } },
23
+ required: ["query"]
24
+ },
25
+ execute: async (_input, context) => {
26
+ return {
27
+ note: `Query would execute in tenant ${context.tenantId} scope`
28
+ };
29
+ }
30
+ };
31
+ var knowledgeBaseTool = {
32
+ name: "knowledge_base",
33
+ description: "Search the organization's knowledge base for relevant documents",
34
+ inputSchema: {
35
+ type: "object",
36
+ properties: {
37
+ query: { type: "string" },
38
+ limit: { type: "number" }
39
+ }
40
+ },
41
+ execute: async (_input, _context) => {
42
+ return { documents: [], note: "Configure vector store for RAG" };
43
+ }
44
+ };
45
+ var BUILT_IN_TOOLS = [
46
+ webSearchTool,
47
+ databaseQueryTool,
48
+ knowledgeBaseTool
49
+ ];
50
+
51
+ export {
52
+ webSearchTool,
53
+ databaseQueryTool,
54
+ knowledgeBaseTool,
55
+ BUILT_IN_TOOLS
56
+ };