@nebutra/agents 1.1.1 → 2.0.0
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.
- package/LICENSE +21 -676
- package/README.md +7 -3
- package/dist/{agent-CahnMASx.d.ts → agent-DDGWuUpe.d.ts} +1 -1
- package/dist/{chunk-B7XWL35G.js → chunk-7VL333VJ.js} +5 -1
- package/dist/{chunk-5LX742GP.js → chunk-C4CC5UEF.js} +25 -53
- package/{src/env.ts → dist/chunk-FCXWOXII.js} +23 -47
- package/dist/chunk-HVLFZW6E.js +71 -0
- package/dist/chunk-HZQXXUKB.js +171 -0
- package/dist/{chunk-RLWM437Q.js → chunk-KC6SOI5Z.js} +19 -4
- package/dist/{chunk-NPQECBXL.js → chunk-S5N743EP.js} +60 -7
- package/dist/chunk-VZPQOXWW.js +47 -0
- package/dist/{chunk-NVPE5EDI.js → chunk-YBCIJKC7.js} +20 -3
- package/dist/env.d.ts +45 -0
- package/dist/env.js +12 -0
- package/dist/fallback.d.ts +100 -0
- package/dist/fallback.js +18 -0
- package/dist/generation/index.d.ts +122 -0
- package/dist/generation/index.js +19 -0
- package/dist/index.d.ts +22 -329
- package/dist/index.js +59 -245
- package/dist/observability.d.ts +46 -0
- package/dist/observability.js +13 -0
- package/dist/providers/langchain.d.ts +2 -2
- package/dist/providers/vercel-ai.d.ts +2 -2
- package/dist/providers/vercel-ai.js +15 -7
- package/dist/sdk/config.d.ts +6 -0
- package/dist/sdk/config.js +2 -1
- package/dist/sdk/index.d.ts +37 -4
- package/dist/sdk/index.js +23 -8
- package/dist/sdk/models.d.ts +20 -27
- package/dist/sdk/models.js +5 -3
- package/dist/sdk/provider.d.ts +1 -0
- package/dist/sdk/provider.js +3 -3
- package/dist/tools.d.ts +1 -1
- package/dist/{types-NtgB3pch.d.ts → types-BytC-HfQ.d.ts} +1 -5
- package/package.json +73 -19
- package/.turbo/turbo-build.log +0 -40
- package/.turbo/turbo-test.log +0 -19
- package/.turbo/turbo-typecheck.log +0 -4
- package/AGENTS.md +0 -63
- package/CHANGELOG.md +0 -36
- package/dist/chunk-5JZJ5KMC.js +0 -37
- package/src/__tests__/cost-observability.test.ts +0 -172
- package/src/__tests__/fallback-wiring.test.ts +0 -313
- package/src/__tests__/generation.test.ts +0 -111
- package/src/__tests__/public-api.test.ts +0 -114
- package/src/__tests__/runtime-gateway.test.ts +0 -108
- package/src/agent.ts +0 -117
- package/src/context.ts +0 -99
- package/src/fallback.ts +0 -358
- package/src/gateway.ts +0 -234
- package/src/generation/index.ts +0 -157
- package/src/generation/mock-provider.ts +0 -123
- package/src/generation/types.ts +0 -87
- package/src/index.ts +0 -104
- package/src/memory.ts +0 -126
- package/src/observability.ts +0 -102
- package/src/orchestrator.ts +0 -147
- package/src/providers/langchain.ts +0 -28
- package/src/providers/vercel-ai.ts +0 -114
- package/src/router.ts +0 -158
- package/src/sdk/config.ts +0 -73
- package/src/sdk/index.ts +0 -214
- package/src/sdk/models.ts +0 -57
- package/src/sdk/provider.ts +0 -80
- package/src/tenant.ts +0 -52
- package/src/tools.ts +0 -65
- package/src/types.ts +0 -114
- package/tsconfig.json +0 -12
- package/tsup.config.ts +0 -21
package/dist/index.js
CHANGED
|
@@ -1,50 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
configure,
|
|
3
|
+
embed,
|
|
4
|
+
embedMany,
|
|
5
|
+
generateStructured,
|
|
6
|
+
generateText,
|
|
7
|
+
getConfig,
|
|
8
|
+
streamText,
|
|
9
|
+
validateStructured
|
|
10
|
+
} from "./chunk-S5N743EP.js";
|
|
11
|
+
import {
|
|
12
|
+
createEmbeddingModel,
|
|
13
|
+
createModel
|
|
14
|
+
} from "./chunk-KC6SOI5Z.js";
|
|
15
|
+
import {
|
|
16
|
+
NebutraAIConfigSchema
|
|
17
|
+
} from "./chunk-YBCIJKC7.js";
|
|
1
18
|
import {
|
|
2
19
|
BUILT_IN_TOOLS,
|
|
3
20
|
databaseQueryTool,
|
|
4
21
|
knowledgeBaseTool,
|
|
5
22
|
webSearchTool
|
|
6
23
|
} from "./chunk-UVL2UVVM.js";
|
|
24
|
+
import {
|
|
25
|
+
_resetGenerationRegistry,
|
|
26
|
+
generateImage,
|
|
27
|
+
generateVideo,
|
|
28
|
+
listGenerationProviders,
|
|
29
|
+
mockGenerationProvider,
|
|
30
|
+
registerGenerationProvider
|
|
31
|
+
} from "./chunk-HZQXXUKB.js";
|
|
32
|
+
import {
|
|
33
|
+
OPENAI_MAX_PROPERTY_NAME_LENGTH,
|
|
34
|
+
assertSafeOpenAIJsonPayload,
|
|
35
|
+
findOversizedPropertyName
|
|
36
|
+
} from "./chunk-VZPQOXWW.js";
|
|
7
37
|
import {
|
|
8
38
|
buildTelemetryConfig,
|
|
9
39
|
flushTelemetry,
|
|
10
40
|
initLangfuse
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
BaseAgent,
|
|
14
|
-
clearMemory,
|
|
15
|
-
getMemory,
|
|
16
|
-
saveMemory
|
|
17
|
-
} from "./chunk-RDOFKRI6.js";
|
|
41
|
+
} from "./chunk-7VL333VJ.js";
|
|
18
42
|
import {
|
|
19
|
-
configure,
|
|
20
|
-
embed,
|
|
21
|
-
embedMany,
|
|
22
|
-
generateText,
|
|
23
|
-
getConfig,
|
|
24
|
-
streamText
|
|
25
|
-
} from "./chunk-NPQECBXL.js";
|
|
26
|
-
import {
|
|
27
|
-
AgentsEnvSchema,
|
|
28
43
|
buildSystemWithCache,
|
|
29
44
|
filterAvailableProviders,
|
|
30
|
-
getAgentsEnv,
|
|
31
|
-
isLangfuseConfigured,
|
|
32
45
|
isRetryableError,
|
|
33
46
|
runEmbedWithFallback,
|
|
34
47
|
runWithFallback,
|
|
35
48
|
withAnthropicCacheControl
|
|
36
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-C4CC5UEF.js";
|
|
37
50
|
import {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
models,
|
|
52
|
+
resolveModel,
|
|
53
|
+
toAi302ModelId
|
|
54
|
+
} from "./chunk-HVLFZW6E.js";
|
|
41
55
|
import {
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
AgentsEnvSchema,
|
|
57
|
+
getAgentsEnv,
|
|
58
|
+
isLangfuseConfigured
|
|
59
|
+
} from "./chunk-FCXWOXII.js";
|
|
44
60
|
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
61
|
+
BaseAgent,
|
|
62
|
+
clearMemory,
|
|
63
|
+
getMemory,
|
|
64
|
+
saveMemory
|
|
65
|
+
} from "./chunk-RDOFKRI6.js";
|
|
48
66
|
|
|
49
67
|
// src/context.ts
|
|
50
68
|
var MAX_BIO_CHARS = 2e3;
|
|
@@ -94,170 +112,8 @@ function buildPersonalizedSystemPrompt(basePrompt, context) {
|
|
|
94
112
|
${basePrompt}`;
|
|
95
113
|
}
|
|
96
114
|
|
|
97
|
-
// src/generation/index.ts
|
|
98
|
-
import { logger } from "@nebutra/logger";
|
|
99
|
-
|
|
100
|
-
// src/generation/mock-provider.ts
|
|
101
|
-
function hash(input) {
|
|
102
|
-
let h = 2166136261;
|
|
103
|
-
for (let i = 0; i < input.length; i++) {
|
|
104
|
-
h ^= input.charCodeAt(i);
|
|
105
|
-
h = Math.imul(h, 16777619);
|
|
106
|
-
}
|
|
107
|
-
return h >>> 0;
|
|
108
|
-
}
|
|
109
|
-
function escapeXml(s) {
|
|
110
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
111
|
-
}
|
|
112
|
-
function svgDataUri(label, prompt, w, h) {
|
|
113
|
-
const hue = hash(prompt) % 360;
|
|
114
|
-
const hue2 = (hue + 40) % 360;
|
|
115
|
-
const words = prompt.split(/\s+/);
|
|
116
|
-
const lines = [];
|
|
117
|
-
let cur = "";
|
|
118
|
-
for (const word of words) {
|
|
119
|
-
if ((cur + " " + word).trim().length > 32) {
|
|
120
|
-
lines.push(cur.trim());
|
|
121
|
-
cur = word;
|
|
122
|
-
} else {
|
|
123
|
-
cur = `${cur} ${word}`;
|
|
124
|
-
}
|
|
125
|
-
if (lines.length === 4) break;
|
|
126
|
-
}
|
|
127
|
-
if (cur && lines.length < 4) lines.push(cur.trim());
|
|
128
|
-
const tspans = lines.map((ln, i) => `<tspan x="50%" dy="${i === 0 ? 0 : 26}">${escapeXml(ln)}</tspan>`).join("");
|
|
129
|
-
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">
|
|
130
|
-
<defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
|
131
|
-
<stop offset="0" stop-color="hsl(${hue} 70% 55%)"/>
|
|
132
|
-
<stop offset="1" stop-color="hsl(${hue2} 70% 45%)"/>
|
|
133
|
-
</linearGradient></defs>
|
|
134
|
-
<rect width="${w}" height="${h}" fill="url(#g)"/>
|
|
135
|
-
<text x="50%" y="14%" fill="rgba(255,255,255,.7)" font-family="sans-serif" font-size="20" text-anchor="middle">${escapeXml(label)}</text>
|
|
136
|
-
<text x="50%" y="46%" fill="#fff" font-family="sans-serif" font-size="22" font-weight="600" text-anchor="middle">${tspans}</text>
|
|
137
|
-
</svg>`;
|
|
138
|
-
const b64 = typeof btoa === "function" ? btoa(unescape(encodeURIComponent(svg))) : Buffer.from(svg, "utf8").toString("base64");
|
|
139
|
-
return `data:image/svg+xml;base64,${b64}`;
|
|
140
|
-
}
|
|
141
|
-
var mockGenerationProvider = {
|
|
142
|
-
name: "mock",
|
|
143
|
-
envKey: null,
|
|
144
|
-
capabilities: ["image", "video"],
|
|
145
|
-
async generateImage(req, _ctx) {
|
|
146
|
-
const width = req.width ?? 1024;
|
|
147
|
-
const height = req.height ?? 1024;
|
|
148
|
-
return {
|
|
149
|
-
modality: "image",
|
|
150
|
-
mimeType: "image/svg+xml",
|
|
151
|
-
url: svgDataUri("mock \xB7 image", req.prompt, width, height),
|
|
152
|
-
width,
|
|
153
|
-
height,
|
|
154
|
-
providerName: "mock",
|
|
155
|
-
model: req.model ?? "mock-image-1",
|
|
156
|
-
usage: { units: 1 }
|
|
157
|
-
};
|
|
158
|
-
},
|
|
159
|
-
async generateVideo(req, _ctx) {
|
|
160
|
-
const width = req.width ?? 1280;
|
|
161
|
-
const height = req.height ?? 720;
|
|
162
|
-
const seconds = req.durationSeconds ?? 5;
|
|
163
|
-
return {
|
|
164
|
-
modality: "video",
|
|
165
|
-
mimeType: "image/svg+xml",
|
|
166
|
-
url: svgDataUri(`mock \xB7 video \xB7 ${seconds}s`, req.prompt, width, height),
|
|
167
|
-
width,
|
|
168
|
-
height,
|
|
169
|
-
providerName: "mock",
|
|
170
|
-
model: req.model ?? "mock-video-1",
|
|
171
|
-
usage: { units: seconds }
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
// src/generation/index.ts
|
|
177
|
-
var log = logger.child({ module: "agents/generation" });
|
|
178
|
-
var _registry = /* @__PURE__ */ new Map();
|
|
179
|
-
function registerGenerationProvider(provider) {
|
|
180
|
-
_registry.set(provider.name, provider);
|
|
181
|
-
}
|
|
182
|
-
function _resetGenerationRegistry() {
|
|
183
|
-
_registry.clear();
|
|
184
|
-
_registry.set(mockGenerationProvider.name, mockGenerationProvider);
|
|
185
|
-
}
|
|
186
|
-
_resetGenerationRegistry();
|
|
187
|
-
function hasEnvKey(provider) {
|
|
188
|
-
if (provider.envKey === null) return true;
|
|
189
|
-
return Boolean(globalThis.process?.env?.[provider.envKey]);
|
|
190
|
-
}
|
|
191
|
-
function listGenerationProviders(modality, options = {}) {
|
|
192
|
-
const envChain = (globalThis.process?.env?.GENERATION_FALLBACK_CHAIN ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
193
|
-
const preferred = options.chain ?? (envChain.length > 0 ? envChain : []);
|
|
194
|
-
const mockName = mockGenerationProvider.name;
|
|
195
|
-
const all = [...preferred, ..._registry.keys()];
|
|
196
|
-
const seen = /* @__PURE__ */ new Set();
|
|
197
|
-
const resolved = [];
|
|
198
|
-
for (const name of all) {
|
|
199
|
-
if (seen.has(name) || name === mockName) continue;
|
|
200
|
-
seen.add(name);
|
|
201
|
-
const provider = _registry.get(name);
|
|
202
|
-
if (!provider) continue;
|
|
203
|
-
if (!provider.capabilities.includes(modality)) continue;
|
|
204
|
-
if (!hasEnvKey(provider)) continue;
|
|
205
|
-
resolved.push(name);
|
|
206
|
-
}
|
|
207
|
-
resolved.push(mockName);
|
|
208
|
-
return resolved;
|
|
209
|
-
}
|
|
210
|
-
async function runChain(modality, options, ctx, invoke) {
|
|
211
|
-
const chain = listGenerationProviders(modality, options);
|
|
212
|
-
let lastErr;
|
|
213
|
-
for (const name of chain) {
|
|
214
|
-
const provider = _registry.get(name);
|
|
215
|
-
if (!provider) continue;
|
|
216
|
-
try {
|
|
217
|
-
const result = await invoke(provider);
|
|
218
|
-
log.debug("generation succeeded", {
|
|
219
|
-
provider: name,
|
|
220
|
-
modality,
|
|
221
|
-
tenantId: ctx.tenantId
|
|
222
|
-
});
|
|
223
|
-
return result;
|
|
224
|
-
} catch (err) {
|
|
225
|
-
lastErr = err;
|
|
226
|
-
const retryable = isRetryableError(err);
|
|
227
|
-
log.warn("generation provider failed", {
|
|
228
|
-
provider: name,
|
|
229
|
-
modality,
|
|
230
|
-
retryable,
|
|
231
|
-
tenantId: ctx.tenantId
|
|
232
|
-
});
|
|
233
|
-
if (!retryable && name !== mockGenerationProvider.name) continue;
|
|
234
|
-
if (!retryable) throw err;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
throw lastErr instanceof Error ? lastErr : new Error("[@nebutra/agents] generation chain exhausted");
|
|
238
|
-
}
|
|
239
|
-
async function generateImage(req, ctx, options = {}) {
|
|
240
|
-
return runChain("image", options, ctx, (p) => {
|
|
241
|
-
if (!p.generateImage) {
|
|
242
|
-
throw new Error(`[@nebutra/agents] provider "${p.name}" lacks image support`);
|
|
243
|
-
}
|
|
244
|
-
return p.generateImage(req, ctx);
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
async function generateVideo(req, ctx, options = {}) {
|
|
248
|
-
return runChain("video", options, ctx, (p) => {
|
|
249
|
-
if (!p.generateVideo) {
|
|
250
|
-
throw new Error(`[@nebutra/agents] provider "${p.name}" lacks video support`);
|
|
251
|
-
}
|
|
252
|
-
return p.generateVideo(req, ctx);
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// src/orchestrator.ts
|
|
257
|
-
import { logger as logger3 } from "@nebutra/logger";
|
|
258
|
-
|
|
259
115
|
// src/router.ts
|
|
260
|
-
import { logger
|
|
116
|
+
import { logger } from "@nebutra/logger";
|
|
261
117
|
var AgentRouter = class {
|
|
262
118
|
config;
|
|
263
119
|
constructor(config) {
|
|
@@ -309,7 +165,7 @@ var AgentRouter = class {
|
|
|
309
165
|
bestId = agent.id;
|
|
310
166
|
}
|
|
311
167
|
}
|
|
312
|
-
|
|
168
|
+
logger.info("Router: keyword match", {
|
|
313
169
|
selectedAgentId: bestId,
|
|
314
170
|
score: bestScore
|
|
315
171
|
});
|
|
@@ -340,14 +196,14 @@ ${agentList}`,
|
|
|
340
196
|
const selectedId = result.text.trim();
|
|
341
197
|
const validAgent = agents.find((a) => a.id === selectedId);
|
|
342
198
|
if (validAgent) {
|
|
343
|
-
|
|
199
|
+
logger.info("Router: LLM classification", {
|
|
344
200
|
selectedAgentId: validAgent.id
|
|
345
201
|
});
|
|
346
202
|
return validAgent.id;
|
|
347
203
|
}
|
|
348
204
|
return defaultAgentId ?? agents[0]?.id;
|
|
349
205
|
} catch (error) {
|
|
350
|
-
|
|
206
|
+
logger.warn("Router: LLM routing failed, falling back to keyword", {
|
|
351
207
|
error
|
|
352
208
|
});
|
|
353
209
|
return this.routeByKeyword(message, agents, defaultAgentId);
|
|
@@ -365,7 +221,7 @@ ${agentList}`,
|
|
|
365
221
|
try {
|
|
366
222
|
return await this.config.customRouter(message, context);
|
|
367
223
|
} catch (error) {
|
|
368
|
-
|
|
224
|
+
logger.warn("Router: custom router failed", { error });
|
|
369
225
|
if (defaultAgentId) return defaultAgentId;
|
|
370
226
|
throw error;
|
|
371
227
|
}
|
|
@@ -414,15 +270,11 @@ var AgentOrchestrator = class {
|
|
|
414
270
|
registerAgent(agent) {
|
|
415
271
|
this.agents.set(agent.config.id, agent);
|
|
416
272
|
}
|
|
417
|
-
/**
|
|
418
|
-
* Get a registered agent by ID.
|
|
419
|
-
*/
|
|
273
|
+
/** Get a registered agent by ID. */
|
|
420
274
|
getAgent(agentId) {
|
|
421
275
|
return this.agents.get(agentId);
|
|
422
276
|
}
|
|
423
|
-
/**
|
|
424
|
-
* Route a message to the best agent and execute.
|
|
425
|
-
*/
|
|
277
|
+
/** Route a message to the best agent and execute. */
|
|
426
278
|
async chat(message, context) {
|
|
427
279
|
await this.assertQuota(context.tenantId);
|
|
428
280
|
const agentConfigs = [...this.agents.values()].map((a) => a.config);
|
|
@@ -434,51 +286,7 @@ var AgentOrchestrator = class {
|
|
|
434
286
|
const messages = [{ role: "user", content: message, timestamp: /* @__PURE__ */ new Date() }];
|
|
435
287
|
return agent.run(messages, context);
|
|
436
288
|
}
|
|
437
|
-
/**
|
|
438
|
-
* Execute a multi-agent pipeline where each step's output feeds the next.
|
|
439
|
-
* @experimental — API may change. Use `chat()` for production workloads.
|
|
440
|
-
*/
|
|
441
|
-
async pipeline(steps, input, context) {
|
|
442
|
-
await this.assertQuota(context.tenantId);
|
|
443
|
-
let currentInput = input;
|
|
444
|
-
let lastResponse;
|
|
445
|
-
for (const step of steps) {
|
|
446
|
-
const agent = this.agents.get(step.agentId);
|
|
447
|
-
if (!agent) {
|
|
448
|
-
throw new Error(`Pipeline step references unknown agent "${step.agentId}"`);
|
|
449
|
-
}
|
|
450
|
-
const transformedInput = step.transformInput ? step.transformInput(currentInput) : currentInput;
|
|
451
|
-
const messages = [
|
|
452
|
-
{ role: "user", content: transformedInput, timestamp: /* @__PURE__ */ new Date() }
|
|
453
|
-
];
|
|
454
|
-
lastResponse = await agent.run(messages, context);
|
|
455
|
-
const assistantMessages = lastResponse.messages.filter((m) => m.role === "assistant");
|
|
456
|
-
const lastAssistant = assistantMessages[assistantMessages.length - 1];
|
|
457
|
-
currentInput = lastAssistant?.content ?? "";
|
|
458
|
-
logger3.info("Pipeline step completed", {
|
|
459
|
-
agentId: step.agentId,
|
|
460
|
-
tenantId: context.tenantId
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
if (!lastResponse) {
|
|
464
|
-
throw new Error("Pipeline produced no response (empty steps?)");
|
|
465
|
-
}
|
|
466
|
-
return lastResponse;
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Broadcast a message to ALL registered agents in parallel.
|
|
470
|
-
* Returns an array of responses (one per agent).
|
|
471
|
-
* @experimental — API may change. Use `chat()` for production workloads.
|
|
472
|
-
*/
|
|
473
|
-
async broadcast(message, context) {
|
|
474
|
-
await this.assertQuota(context.tenantId);
|
|
475
|
-
const messages = [{ role: "user", content: message, timestamp: /* @__PURE__ */ new Date() }];
|
|
476
|
-
const promises = [...this.agents.values()].map((agent) => agent.run(messages, context));
|
|
477
|
-
return Promise.all(promises);
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Check tenant quota before execution.
|
|
481
|
-
*/
|
|
289
|
+
/** Check tenant quota before execution. */
|
|
482
290
|
async assertQuota(tenantId) {
|
|
483
291
|
const { allowed } = await checkAgentQuota(tenantId);
|
|
484
292
|
if (!allowed) {
|
|
@@ -493,7 +301,9 @@ export {
|
|
|
493
301
|
BUILT_IN_TOOLS,
|
|
494
302
|
BaseAgent,
|
|
495
303
|
NebutraAIConfigSchema,
|
|
304
|
+
OPENAI_MAX_PROPERTY_NAME_LENGTH,
|
|
496
305
|
_resetGenerationRegistry,
|
|
306
|
+
assertSafeOpenAIJsonPayload,
|
|
497
307
|
buildPersonalizedSystemPrompt,
|
|
498
308
|
buildSystemWithCache,
|
|
499
309
|
buildTelemetryConfig,
|
|
@@ -507,8 +317,10 @@ export {
|
|
|
507
317
|
embed,
|
|
508
318
|
embedMany,
|
|
509
319
|
filterAvailableProviders,
|
|
320
|
+
findOversizedPropertyName,
|
|
510
321
|
flushTelemetry,
|
|
511
322
|
generateImage,
|
|
323
|
+
generateStructured,
|
|
512
324
|
generateText,
|
|
513
325
|
generateVideo,
|
|
514
326
|
getAgentsEnv,
|
|
@@ -528,6 +340,8 @@ export {
|
|
|
528
340
|
runWithFallback,
|
|
529
341
|
saveMemory,
|
|
530
342
|
streamText,
|
|
343
|
+
toAi302ModelId,
|
|
344
|
+
validateStructured,
|
|
531
345
|
webSearchTool,
|
|
532
346
|
withAnthropicCacheControl
|
|
533
347
|
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM observability via Langfuse.
|
|
3
|
+
*
|
|
4
|
+
* - No-op when env vars are missing — the package works with zero config.
|
|
5
|
+
* - Exposes `experimental_telemetry` settings ready to plug into Vercel AI SDK.
|
|
6
|
+
* - Use `LangfuseExporter` from `langfuse-vercel` in your OTEL NodeSDK setup
|
|
7
|
+
* for full trace export (see README).
|
|
8
|
+
*/
|
|
9
|
+
type LangfuseClient = {
|
|
10
|
+
trace: (input: unknown) => unknown;
|
|
11
|
+
flushAsync: () => Promise<void>;
|
|
12
|
+
shutdownAsync: () => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Returns a configured `Langfuse` client, or `null` when env is missing.
|
|
16
|
+
*
|
|
17
|
+
* Telemetry is OPTIONAL. If LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY are
|
|
18
|
+
* not set, this returns null (no error). Callers must handle the null case.
|
|
19
|
+
*/
|
|
20
|
+
declare function initLangfuse(): Promise<LangfuseClient | null>;
|
|
21
|
+
/** Test helper — clears cached client so subsequent init() re-reads env. */
|
|
22
|
+
declare function _resetLangfuseCache(): void;
|
|
23
|
+
interface TelemetryMetadata {
|
|
24
|
+
tenantId?: string | undefined;
|
|
25
|
+
userId?: string | undefined;
|
|
26
|
+
sessionId?: string | undefined;
|
|
27
|
+
agentId?: string | undefined;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build the `experimental_telemetry` option for AI SDK calls.
|
|
32
|
+
* Returns `{ isEnabled: false }` (a safe no-op) when Langfuse is not configured,
|
|
33
|
+
* which avoids any OTEL span creation cost.
|
|
34
|
+
*/
|
|
35
|
+
declare function buildTelemetryConfig(args: {
|
|
36
|
+
functionId: string;
|
|
37
|
+
metadata?: TelemetryMetadata;
|
|
38
|
+
}): {
|
|
39
|
+
isEnabled: boolean;
|
|
40
|
+
functionId?: string;
|
|
41
|
+
metadata?: Record<string, unknown>;
|
|
42
|
+
};
|
|
43
|
+
/** Flush pending telemetry before process exit. Safe to call when disabled. */
|
|
44
|
+
declare function flushTelemetry(): Promise<void>;
|
|
45
|
+
|
|
46
|
+
export { type TelemetryMetadata, _resetLangfuseCache, buildTelemetryConfig, flushTelemetry, initLangfuse };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BaseAgent } from '../agent-
|
|
2
|
-
import { c as AgentConfig } from '../types-
|
|
1
|
+
import { B as BaseAgent } from '../agent-DDGWuUpe.js';
|
|
2
|
+
import { c as AgentConfig } from '../types-BytC-HfQ.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* LangChain.js agent adapter — stub.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BaseAgent } from '../agent-
|
|
2
|
-
import { A as AgentMessage, a as AgentContext, b as AgentResponse } from '../types-
|
|
1
|
+
import { B as BaseAgent } from '../agent-DDGWuUpe.js';
|
|
2
|
+
import { A as AgentMessage, a as AgentContext, b as AgentResponse } from '../types-BytC-HfQ.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Vercel AI SDK agent adapter.
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "../chunk-
|
|
2
|
+
assertSafeOpenAIJsonPayload
|
|
3
|
+
} from "../chunk-VZPQOXWW.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
} from "../chunk-
|
|
5
|
+
buildTelemetryConfig
|
|
6
|
+
} from "../chunk-7VL333VJ.js";
|
|
7
7
|
import {
|
|
8
8
|
runWithFallback,
|
|
9
9
|
withAnthropicCacheControl
|
|
10
|
-
} from "../chunk-
|
|
11
|
-
import "../chunk-
|
|
10
|
+
} from "../chunk-C4CC5UEF.js";
|
|
11
|
+
import "../chunk-HVLFZW6E.js";
|
|
12
|
+
import "../chunk-FCXWOXII.js";
|
|
13
|
+
import {
|
|
14
|
+
BaseAgent
|
|
15
|
+
} from "../chunk-RDOFKRI6.js";
|
|
12
16
|
|
|
13
17
|
// src/providers/vercel-ai.ts
|
|
14
18
|
var VercelAIAgent = class extends BaseAgent {
|
|
@@ -19,7 +23,7 @@ var VercelAIAgent = class extends BaseAgent {
|
|
|
19
23
|
t.name,
|
|
20
24
|
dynamicTool({
|
|
21
25
|
description: t.description,
|
|
22
|
-
inputSchema: t.inputSchema,
|
|
26
|
+
inputSchema: assertSafeToolSchema(t.name, t.inputSchema),
|
|
23
27
|
execute: async (args) => t.execute(args, context)
|
|
24
28
|
})
|
|
25
29
|
])
|
|
@@ -78,6 +82,10 @@ var VercelAIAgent = class extends BaseAgent {
|
|
|
78
82
|
};
|
|
79
83
|
}
|
|
80
84
|
};
|
|
85
|
+
function assertSafeToolSchema(name, inputSchema) {
|
|
86
|
+
assertSafeOpenAIJsonPayload(`OpenAI tool schema "${name}"`, inputSchema);
|
|
87
|
+
return inputSchema;
|
|
88
|
+
}
|
|
81
89
|
export {
|
|
82
90
|
VercelAIAgent
|
|
83
91
|
};
|
package/dist/sdk/config.d.ts
CHANGED
|
@@ -15,12 +15,16 @@ import { z } from 'zod';
|
|
|
15
15
|
* - openrouter: 300+ models, automatic failover, pay-as-you-go (default)
|
|
16
16
|
* - openai: Direct OpenAI API access
|
|
17
17
|
* - siliconflow: SiliconFlow cloud — Qwen, DeepSeek, etc. (OpenAI-compatible, China-optimized)
|
|
18
|
+
* - sensenova: 商汤 SenseNova — OpenAI-compatible (`compatible-mode/v1`)
|
|
19
|
+
* - ai302: 302.AI aggregator — OpenAI-compatible, broad model catalogue
|
|
18
20
|
* - gateway: Vercel AI Gateway with OIDC auth (for Vercel-deployed apps)
|
|
19
21
|
*/
|
|
20
22
|
declare const ProviderType: z.ZodEnum<{
|
|
21
23
|
openrouter: "openrouter";
|
|
22
24
|
openai: "openai";
|
|
25
|
+
ai302: "ai302";
|
|
23
26
|
siliconflow: "siliconflow";
|
|
27
|
+
sensenova: "sensenova";
|
|
24
28
|
gateway: "gateway";
|
|
25
29
|
}>;
|
|
26
30
|
type ProviderType = z.infer<typeof ProviderType>;
|
|
@@ -28,7 +32,9 @@ declare const NebutraAIConfigSchema: z.ZodObject<{
|
|
|
28
32
|
provider: z.ZodDefault<z.ZodEnum<{
|
|
29
33
|
openrouter: "openrouter";
|
|
30
34
|
openai: "openai";
|
|
35
|
+
ai302: "ai302";
|
|
31
36
|
siliconflow: "siliconflow";
|
|
37
|
+
sensenova: "sensenova";
|
|
32
38
|
gateway: "gateway";
|
|
33
39
|
}>>;
|
|
34
40
|
apiKey: z.ZodOptional<z.ZodString>;
|
package/dist/sdk/config.js
CHANGED
package/dist/sdk/index.d.ts
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
1
|
import * as ai from 'ai';
|
|
2
|
-
import {
|
|
2
|
+
import { ModelMessage, JSONValue, GenerateTextResult, StreamTextResult } from 'ai';
|
|
3
3
|
export { GenerateTextResult, ModelMessage, StreamTextResult } from 'ai';
|
|
4
4
|
import { NebutraAIConfig, ResolvedNebutraAIConfig } from './config.js';
|
|
5
5
|
export { NebutraAIConfigSchema, ProviderType } from './config.js';
|
|
6
|
-
export { ModelPreset, models, resolveModel } from './models.js';
|
|
6
|
+
export { ModelPreset, models, resolveModel, toAi302ModelId } from './models.js';
|
|
7
7
|
export { createEmbeddingModel, createModel } from './provider.js';
|
|
8
8
|
import 'zod';
|
|
9
9
|
|
|
10
|
+
declare const OPENAI_MAX_PROPERTY_NAME_LENGTH = 256;
|
|
11
|
+
interface OversizedPropertyNameIssue {
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly length: number;
|
|
14
|
+
}
|
|
15
|
+
declare function findOversizedPropertyName(value: unknown, maxLength?: number): OversizedPropertyNameIssue | null;
|
|
16
|
+
declare function assertSafeOpenAIJsonPayload(label: string, value: unknown): void;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Structured generation — the JSON-Schema → forced-tool bridge.
|
|
20
|
+
*
|
|
21
|
+
* AI SDK v6 removed `generateObject`. To get a schema-shaped object we force a
|
|
22
|
+
* single `_output` tool whose `inputSchema` IS the caller's JSON Schema, then
|
|
23
|
+
* AJV-recheck the model's tool-call args (defense in depth — the provider's
|
|
24
|
+
* structured output should already match, but tenants supply the schema). The
|
|
25
|
+
* call goes through the same provider fallback chain as every other generation.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
interface GenerateStructuredResult {
|
|
29
|
+
/** The object the model produced — already validated against the schema. */
|
|
30
|
+
readonly output: unknown;
|
|
31
|
+
readonly usage: {
|
|
32
|
+
readonly inputTokens: number;
|
|
33
|
+
readonly outputTokens: number;
|
|
34
|
+
readonly reasoningOutputTokens: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Validate a value against a JSON Schema. Throws with a readable message. */
|
|
38
|
+
declare function validateStructured(value: unknown, schema: Record<string, unknown>): void;
|
|
39
|
+
declare function generateStructured(messages: ModelMessage[], schema: Record<string, unknown>, options?: {
|
|
40
|
+
model?: string;
|
|
41
|
+
}): Promise<GenerateStructuredResult>;
|
|
42
|
+
|
|
10
43
|
/**
|
|
11
44
|
* Initialise the global Nebutra AI configuration.
|
|
12
45
|
* Call once in your app entry point (e.g. instrumentation.ts or layout.tsx).
|
|
@@ -40,7 +73,7 @@ interface StreamFinishEvent {
|
|
|
40
73
|
};
|
|
41
74
|
}
|
|
42
75
|
interface GenerateOptions {
|
|
43
|
-
/** Model ID or preset alias (e.g. "flagship", "fast", "anthropic/claude-sonnet-4"). */
|
|
76
|
+
/** Model ID or preset alias (e.g. "flagship", "fast", "anthropic/claude-sonnet-4.6"). */
|
|
44
77
|
model?: string;
|
|
45
78
|
/** System prompt prepended to the conversation. */
|
|
46
79
|
system?: string;
|
|
@@ -91,4 +124,4 @@ declare function embed(value: string, options?: EmbedOptions): Promise<ai.EmbedR
|
|
|
91
124
|
*/
|
|
92
125
|
declare function embedMany(values: string[], options?: EmbedOptions): Promise<ai.EmbedManyResult>;
|
|
93
126
|
|
|
94
|
-
export { type EmbedOptions, type GenerateOptions, NebutraAIConfig, ResolvedNebutraAIConfig, type StreamFinishEvent, type StreamOptions, configure, embed, embedMany, generateText, getConfig, streamText };
|
|
127
|
+
export { type EmbedOptions, type GenerateOptions, type GenerateStructuredResult, NebutraAIConfig, OPENAI_MAX_PROPERTY_NAME_LENGTH, ResolvedNebutraAIConfig, type StreamFinishEvent, type StreamOptions, assertSafeOpenAIJsonPayload, configure, embed, embedMany, findOversizedPropertyName, generateStructured, generateText, getConfig, streamText, validateStructured };
|
package/dist/sdk/index.js
CHANGED
|
@@ -2,32 +2,47 @@ import {
|
|
|
2
2
|
configure,
|
|
3
3
|
embed,
|
|
4
4
|
embedMany,
|
|
5
|
+
generateStructured,
|
|
5
6
|
generateText,
|
|
6
7
|
getConfig,
|
|
7
|
-
streamText
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
streamText,
|
|
9
|
+
validateStructured
|
|
10
|
+
} from "../chunk-S5N743EP.js";
|
|
10
11
|
import {
|
|
11
12
|
createEmbeddingModel,
|
|
12
13
|
createModel
|
|
13
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-KC6SOI5Z.js";
|
|
14
15
|
import {
|
|
15
16
|
NebutraAIConfigSchema
|
|
16
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-YBCIJKC7.js";
|
|
18
|
+
import {
|
|
19
|
+
OPENAI_MAX_PROPERTY_NAME_LENGTH,
|
|
20
|
+
assertSafeOpenAIJsonPayload,
|
|
21
|
+
findOversizedPropertyName
|
|
22
|
+
} from "../chunk-VZPQOXWW.js";
|
|
23
|
+
import "../chunk-C4CC5UEF.js";
|
|
17
24
|
import {
|
|
18
25
|
models,
|
|
19
|
-
resolveModel
|
|
20
|
-
|
|
26
|
+
resolveModel,
|
|
27
|
+
toAi302ModelId
|
|
28
|
+
} from "../chunk-HVLFZW6E.js";
|
|
29
|
+
import "../chunk-FCXWOXII.js";
|
|
21
30
|
export {
|
|
22
31
|
NebutraAIConfigSchema,
|
|
32
|
+
OPENAI_MAX_PROPERTY_NAME_LENGTH,
|
|
33
|
+
assertSafeOpenAIJsonPayload,
|
|
23
34
|
configure,
|
|
24
35
|
createEmbeddingModel,
|
|
25
36
|
createModel,
|
|
26
37
|
embed,
|
|
27
38
|
embedMany,
|
|
39
|
+
findOversizedPropertyName,
|
|
40
|
+
generateStructured,
|
|
28
41
|
generateText,
|
|
29
42
|
getConfig,
|
|
30
43
|
models,
|
|
31
44
|
resolveModel,
|
|
32
|
-
streamText
|
|
45
|
+
streamText,
|
|
46
|
+
toAi302ModelId,
|
|
47
|
+
validateStructured
|
|
33
48
|
};
|