@nebutra/agents 1.1.0 → 1.1.2
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/{src/env.ts → dist/chunk-BMSL4E4A.js} +23 -47
- package/dist/{chunk-5JZJ5KMC.js → chunk-BZKIMAGK.js} +16 -7
- package/dist/{chunk-NPQECBXL.js → chunk-GRSMUTUS.js} +60 -7
- package/dist/{chunk-B7XWL35G.js → chunk-QYZDHC5A.js} +5 -1
- package/dist/{chunk-RLWM437Q.js → chunk-RNFUEMUB.js} +10 -3
- package/dist/chunk-RWQL4HXC.js +171 -0
- package/dist/{chunk-NVPE5EDI.js → chunk-V6VC2O6Q.js} +4 -3
- package/dist/chunk-VZPQOXWW.js +47 -0
- package/dist/{chunk-5LX742GP.js → chunk-XLBS3XUI.js} +4 -50
- package/dist/env.d.ts +42 -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 +21 -328
- package/dist/index.js +57 -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 +3 -0
- package/dist/sdk/config.js +1 -1
- package/dist/sdk/index.d.ts +36 -3
- package/dist/sdk/index.js +20 -7
- package/dist/sdk/models.d.ts +18 -6
- package/dist/sdk/models.js +1 -1
- 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 -27
- package/.turbo/turbo-build.log +0 -40
- package/.turbo/turbo-test.log +0 -18
- package/.turbo/turbo-typecheck.log +0 -4
- package/AGENTS.md +0 -63
- package/CHANGELOG.md +0 -26
- 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/agent.ts +0 -117
- package/src/context.ts +0 -99
- package/src/fallback.ts +0 -358
- 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,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
configure,
|
|
3
|
+
embed,
|
|
4
|
+
embedMany,
|
|
5
|
+
generateStructured,
|
|
6
|
+
generateText,
|
|
7
|
+
getConfig,
|
|
8
|
+
streamText,
|
|
9
|
+
validateStructured
|
|
10
|
+
} from "./chunk-GRSMUTUS.js";
|
|
11
|
+
import {
|
|
12
|
+
createEmbeddingModel,
|
|
13
|
+
createModel
|
|
14
|
+
} from "./chunk-RNFUEMUB.js";
|
|
15
|
+
import {
|
|
16
|
+
NebutraAIConfigSchema
|
|
17
|
+
} from "./chunk-V6VC2O6Q.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-RWQL4HXC.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-QYZDHC5A.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-
|
|
37
|
-
import {
|
|
38
|
-
createEmbeddingModel,
|
|
39
|
-
createModel
|
|
40
|
-
} from "./chunk-RLWM437Q.js";
|
|
41
|
-
import {
|
|
42
|
-
NebutraAIConfigSchema
|
|
43
|
-
} from "./chunk-NVPE5EDI.js";
|
|
49
|
+
} from "./chunk-XLBS3XUI.js";
|
|
44
50
|
import {
|
|
45
51
|
models,
|
|
46
52
|
resolveModel
|
|
47
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-BZKIMAGK.js";
|
|
54
|
+
import {
|
|
55
|
+
AgentsEnvSchema,
|
|
56
|
+
getAgentsEnv,
|
|
57
|
+
isLangfuseConfigured
|
|
58
|
+
} from "./chunk-BMSL4E4A.js";
|
|
59
|
+
import {
|
|
60
|
+
BaseAgent,
|
|
61
|
+
clearMemory,
|
|
62
|
+
getMemory,
|
|
63
|
+
saveMemory
|
|
64
|
+
} from "./chunk-RDOFKRI6.js";
|
|
48
65
|
|
|
49
66
|
// src/context.ts
|
|
50
67
|
var MAX_BIO_CHARS = 2e3;
|
|
@@ -94,170 +111,8 @@ function buildPersonalizedSystemPrompt(basePrompt, context) {
|
|
|
94
111
|
${basePrompt}`;
|
|
95
112
|
}
|
|
96
113
|
|
|
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
114
|
// src/router.ts
|
|
260
|
-
import { logger
|
|
115
|
+
import { logger } from "@nebutra/logger";
|
|
261
116
|
var AgentRouter = class {
|
|
262
117
|
config;
|
|
263
118
|
constructor(config) {
|
|
@@ -309,7 +164,7 @@ var AgentRouter = class {
|
|
|
309
164
|
bestId = agent.id;
|
|
310
165
|
}
|
|
311
166
|
}
|
|
312
|
-
|
|
167
|
+
logger.info("Router: keyword match", {
|
|
313
168
|
selectedAgentId: bestId,
|
|
314
169
|
score: bestScore
|
|
315
170
|
});
|
|
@@ -340,14 +195,14 @@ ${agentList}`,
|
|
|
340
195
|
const selectedId = result.text.trim();
|
|
341
196
|
const validAgent = agents.find((a) => a.id === selectedId);
|
|
342
197
|
if (validAgent) {
|
|
343
|
-
|
|
198
|
+
logger.info("Router: LLM classification", {
|
|
344
199
|
selectedAgentId: validAgent.id
|
|
345
200
|
});
|
|
346
201
|
return validAgent.id;
|
|
347
202
|
}
|
|
348
203
|
return defaultAgentId ?? agents[0]?.id;
|
|
349
204
|
} catch (error) {
|
|
350
|
-
|
|
205
|
+
logger.warn("Router: LLM routing failed, falling back to keyword", {
|
|
351
206
|
error
|
|
352
207
|
});
|
|
353
208
|
return this.routeByKeyword(message, agents, defaultAgentId);
|
|
@@ -365,7 +220,7 @@ ${agentList}`,
|
|
|
365
220
|
try {
|
|
366
221
|
return await this.config.customRouter(message, context);
|
|
367
222
|
} catch (error) {
|
|
368
|
-
|
|
223
|
+
logger.warn("Router: custom router failed", { error });
|
|
369
224
|
if (defaultAgentId) return defaultAgentId;
|
|
370
225
|
throw error;
|
|
371
226
|
}
|
|
@@ -414,15 +269,11 @@ var AgentOrchestrator = class {
|
|
|
414
269
|
registerAgent(agent) {
|
|
415
270
|
this.agents.set(agent.config.id, agent);
|
|
416
271
|
}
|
|
417
|
-
/**
|
|
418
|
-
* Get a registered agent by ID.
|
|
419
|
-
*/
|
|
272
|
+
/** Get a registered agent by ID. */
|
|
420
273
|
getAgent(agentId) {
|
|
421
274
|
return this.agents.get(agentId);
|
|
422
275
|
}
|
|
423
|
-
/**
|
|
424
|
-
* Route a message to the best agent and execute.
|
|
425
|
-
*/
|
|
276
|
+
/** Route a message to the best agent and execute. */
|
|
426
277
|
async chat(message, context) {
|
|
427
278
|
await this.assertQuota(context.tenantId);
|
|
428
279
|
const agentConfigs = [...this.agents.values()].map((a) => a.config);
|
|
@@ -434,51 +285,7 @@ var AgentOrchestrator = class {
|
|
|
434
285
|
const messages = [{ role: "user", content: message, timestamp: /* @__PURE__ */ new Date() }];
|
|
435
286
|
return agent.run(messages, context);
|
|
436
287
|
}
|
|
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
|
-
*/
|
|
288
|
+
/** Check tenant quota before execution. */
|
|
482
289
|
async assertQuota(tenantId) {
|
|
483
290
|
const { allowed } = await checkAgentQuota(tenantId);
|
|
484
291
|
if (!allowed) {
|
|
@@ -493,7 +300,9 @@ export {
|
|
|
493
300
|
BUILT_IN_TOOLS,
|
|
494
301
|
BaseAgent,
|
|
495
302
|
NebutraAIConfigSchema,
|
|
303
|
+
OPENAI_MAX_PROPERTY_NAME_LENGTH,
|
|
496
304
|
_resetGenerationRegistry,
|
|
305
|
+
assertSafeOpenAIJsonPayload,
|
|
497
306
|
buildPersonalizedSystemPrompt,
|
|
498
307
|
buildSystemWithCache,
|
|
499
308
|
buildTelemetryConfig,
|
|
@@ -507,8 +316,10 @@ export {
|
|
|
507
316
|
embed,
|
|
508
317
|
embedMany,
|
|
509
318
|
filterAvailableProviders,
|
|
319
|
+
findOversizedPropertyName,
|
|
510
320
|
flushTelemetry,
|
|
511
321
|
generateImage,
|
|
322
|
+
generateStructured,
|
|
512
323
|
generateText,
|
|
513
324
|
generateVideo,
|
|
514
325
|
getAgentsEnv,
|
|
@@ -528,6 +339,7 @@ export {
|
|
|
528
339
|
runWithFallback,
|
|
529
340
|
saveMemory,
|
|
530
341
|
streamText,
|
|
342
|
+
validateStructured,
|
|
531
343
|
webSearchTool,
|
|
532
344
|
withAnthropicCacheControl
|
|
533
345
|
};
|
|
@@ -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-QYZDHC5A.js";
|
|
7
7
|
import {
|
|
8
8
|
runWithFallback,
|
|
9
9
|
withAnthropicCacheControl
|
|
10
|
-
} from "../chunk-
|
|
11
|
-
import "../chunk-
|
|
10
|
+
} from "../chunk-XLBS3XUI.js";
|
|
11
|
+
import "../chunk-BZKIMAGK.js";
|
|
12
|
+
import "../chunk-BMSL4E4A.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,14 @@ 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`)
|
|
18
19
|
* - gateway: Vercel AI Gateway with OIDC auth (for Vercel-deployed apps)
|
|
19
20
|
*/
|
|
20
21
|
declare const ProviderType: z.ZodEnum<{
|
|
21
22
|
openrouter: "openrouter";
|
|
22
23
|
openai: "openai";
|
|
23
24
|
siliconflow: "siliconflow";
|
|
25
|
+
sensenova: "sensenova";
|
|
24
26
|
gateway: "gateway";
|
|
25
27
|
}>;
|
|
26
28
|
type ProviderType = z.infer<typeof ProviderType>;
|
|
@@ -29,6 +31,7 @@ declare const NebutraAIConfigSchema: z.ZodObject<{
|
|
|
29
31
|
openrouter: "openrouter";
|
|
30
32
|
openai: "openai";
|
|
31
33
|
siliconflow: "siliconflow";
|
|
34
|
+
sensenova: "sensenova";
|
|
32
35
|
gateway: "gateway";
|
|
33
36
|
}>>;
|
|
34
37
|
apiKey: z.ZodOptional<z.ZodString>;
|
package/dist/sdk/config.js
CHANGED
package/dist/sdk/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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';
|
|
@@ -7,6 +7,39 @@ export { ModelPreset, models, resolveModel } 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,45 @@ 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-GRSMUTUS.js";
|
|
10
11
|
import {
|
|
11
12
|
createEmbeddingModel,
|
|
12
13
|
createModel
|
|
13
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-RNFUEMUB.js";
|
|
14
15
|
import {
|
|
15
16
|
NebutraAIConfigSchema
|
|
16
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-V6VC2O6Q.js";
|
|
18
|
+
import {
|
|
19
|
+
OPENAI_MAX_PROPERTY_NAME_LENGTH,
|
|
20
|
+
assertSafeOpenAIJsonPayload,
|
|
21
|
+
findOversizedPropertyName
|
|
22
|
+
} from "../chunk-VZPQOXWW.js";
|
|
23
|
+
import "../chunk-XLBS3XUI.js";
|
|
17
24
|
import {
|
|
18
25
|
models,
|
|
19
26
|
resolveModel
|
|
20
|
-
} from "../chunk-
|
|
27
|
+
} from "../chunk-BZKIMAGK.js";
|
|
28
|
+
import "../chunk-BMSL4E4A.js";
|
|
21
29
|
export {
|
|
22
30
|
NebutraAIConfigSchema,
|
|
31
|
+
OPENAI_MAX_PROPERTY_NAME_LENGTH,
|
|
32
|
+
assertSafeOpenAIJsonPayload,
|
|
23
33
|
configure,
|
|
24
34
|
createEmbeddingModel,
|
|
25
35
|
createModel,
|
|
26
36
|
embed,
|
|
27
37
|
embedMany,
|
|
38
|
+
findOversizedPropertyName,
|
|
39
|
+
generateStructured,
|
|
28
40
|
generateText,
|
|
29
41
|
getConfig,
|
|
30
42
|
models,
|
|
31
43
|
resolveModel,
|
|
32
|
-
streamText
|
|
44
|
+
streamText,
|
|
45
|
+
validateStructured
|
|
33
46
|
};
|