@yh-ui/ai-sdk 0.1.21

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.
@@ -0,0 +1,882 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createAudioContent = createAudioContent;
7
+ exports.createChainOfThought = createChainOfThought;
8
+ exports.createContextCompressor = createContextCompressor;
9
+ exports.createCostTracker = createCostTracker;
10
+ exports.createImageContent = createImageContent;
11
+ exports.createImageUrlContent = createImageUrlContent;
12
+ exports.createJSONSchema = createJSONSchema;
13
+ exports.createMultiModalMessage = createMultiModalMessage;
14
+ exports.createPlanExecuteAgent = createPlanExecuteAgent;
15
+ exports.createRAGSystem = createRAGSystem;
16
+ exports.createSafetyFilter = createSafetyFilter;
17
+ exports.createTracer = createTracer;
18
+ exports.createVideoContent = createVideoContent;
19
+ exports.fromZodSchema = fromZodSchema;
20
+ exports.parseStructuredOutput = parseStructuredOutput;
21
+ exports.schema = void 0;
22
+ exports.useReActAgent = useReActAgent;
23
+ var _vue = require("vue");
24
+ function useReActAgent(config) {
25
+ const {
26
+ type: _type = "react",
27
+ maxIterations = 10,
28
+ maxToolCalls = 20,
29
+ returnReasoning = false,
30
+ tools = [],
31
+ stopConditions = [],
32
+ onError
33
+ } = config;
34
+ const steps = (0, _vue.ref)([]);
35
+ const isRunning = (0, _vue.ref)(false);
36
+ const currentOutput = (0, _vue.ref)("");
37
+ const toolCallCount = (0, _vue.ref)(0);
38
+ const addStep = step => {
39
+ steps.value.push({
40
+ ...step,
41
+ id: `step-${Date.now()}-${Math.random().toString(36).slice(2)}`,
42
+ timestamp: /* @__PURE__ */new Date()
43
+ });
44
+ };
45
+ const checkStopConditions = output => {
46
+ for (const condition of stopConditions) {
47
+ switch (condition.type) {
48
+ case "contains":
49
+ if (condition.value && output.includes(condition.value)) {
50
+ return true;
51
+ }
52
+ break;
53
+ case "custom":
54
+ if (condition.value && condition.value(output)) {
55
+ return true;
56
+ }
57
+ break;
58
+ }
59
+ }
60
+ return false;
61
+ };
62
+ const executeTool = async (toolName, args) => {
63
+ const tool = tools.find(t => t.name === toolName);
64
+ if (!tool) {
65
+ throw new Error(`Tool not found: ${toolName}`);
66
+ }
67
+ addStep({
68
+ type: "action",
69
+ content: `Executing tool: ${toolName}`,
70
+ toolName,
71
+ toolInput: args
72
+ });
73
+ try {
74
+ const result = await tool.execute(args);
75
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result);
76
+ addStep({
77
+ type: "observation",
78
+ content: resultStr,
79
+ toolName,
80
+ toolOutput: result
81
+ });
82
+ toolCallCount.value++;
83
+ return resultStr;
84
+ } catch (error) {
85
+ addStep({
86
+ type: "observation",
87
+ content: `Error: ${error instanceof Error ? error.message : String(error)}`,
88
+ toolName,
89
+ toolOutput: error
90
+ });
91
+ throw error;
92
+ }
93
+ };
94
+ const parseResponse = response => {
95
+ const thoughtMatch = response.match(/Thought:?\s*(.+)/i);
96
+ const actionMatch = response.match(/Action:?\s*(.+)/i);
97
+ const actionInputMatch = response.match(/Action Input:?\s*(.+)/i);
98
+ return {
99
+ thought: thoughtMatch ? thoughtMatch[1].trim() : response,
100
+ action: actionMatch ? actionMatch[1].trim() : void 0,
101
+ actionInput: actionInputMatch ? actionInputMatch[1].trim() : void 0
102
+ };
103
+ };
104
+ const run = async (input, executeFn) => {
105
+ if (isRunning.value) {
106
+ throw new Error("Agent is already running");
107
+ }
108
+ isRunning.value = true;
109
+ steps.value = [];
110
+ currentOutput.value = "";
111
+ toolCallCount.value = 0;
112
+ let iteration = 0;
113
+ let context = `Task: ${input}
114
+
115
+ `;
116
+ try {
117
+ while (iteration < maxIterations && toolCallCount.value < maxToolCalls) {
118
+ iteration++;
119
+ if (checkStopConditions(currentOutput.value)) {
120
+ break;
121
+ }
122
+ addStep({
123
+ type: "thought",
124
+ content: `Iteration ${iteration}: Thinking about how to proceed...`
125
+ });
126
+ const response = await executeFn(context);
127
+ const parsed = parseResponse(response);
128
+ currentOutput.value = parsed.thought;
129
+ if (parsed.action && parsed.actionInput) {
130
+ try {
131
+ const observation = await executeTool(parsed.action, JSON.parse(parsed.actionInput));
132
+ context += `Thought: ${parsed.thought}
133
+ Action: ${parsed.action}
134
+ Action Input: ${parsed.actionInput}
135
+ Observation: ${observation}
136
+
137
+ `;
138
+ } catch (error) {
139
+ context += `Thought: ${parsed.thought}
140
+ Action: ${parsed.action}
141
+ Action Input: ${parsed.actionInput}
142
+ Observation: Error - ${error instanceof Error ? error.message : String(error)}
143
+
144
+ `;
145
+ if (onError) {
146
+ await onError(error, steps.value[steps.value.length - 1]);
147
+ }
148
+ }
149
+ } else {
150
+ addStep({
151
+ type: "result",
152
+ content: parsed.thought
153
+ });
154
+ break;
155
+ }
156
+ }
157
+ return {
158
+ output: currentOutput.value,
159
+ reasoning: returnReasoning ? steps.value : void 0,
160
+ toolCalls: toolCallCount.value,
161
+ finished: iteration >= maxIterations
162
+ };
163
+ } catch (error) {
164
+ return {
165
+ output: currentOutput.value,
166
+ reasoning: returnReasoning ? steps.value : void 0,
167
+ toolCalls: toolCallCount.value,
168
+ finished: false,
169
+ error: error instanceof Error ? error : new Error(String(error))
170
+ };
171
+ } finally {
172
+ isRunning.value = false;
173
+ }
174
+ };
175
+ return {
176
+ steps,
177
+ isRunning,
178
+ currentOutput,
179
+ toolCallCount,
180
+ run
181
+ };
182
+ }
183
+ function createPlanExecuteAgent(config) {
184
+ const {
185
+ tools = []
186
+ } = config;
187
+ const plans = (0, _vue.ref)([]);
188
+ const currentPlan = (0, _vue.ref)(null);
189
+ const results = (0, _vue.ref)({});
190
+ const executeTool = async (toolName, args) => {
191
+ const tool = tools.find(t => t.name === toolName);
192
+ if (!tool) {
193
+ throw new Error(`Tool not found: ${toolName}`);
194
+ }
195
+ return tool.execute(args);
196
+ };
197
+ const execute = async (task, llm) => {
198
+ const planPrompt = `\u5206\u89E3\u4EE5\u4E0B\u4EFB\u52A1\u4E3A\u591A\u4E2A\u53EF\u6267\u884C\u7684\u6B65\u9AA4\uFF0C\u8FD4\u56DE JSON \u6570\u7EC4\u683C\u5F0F\uFF1A
199
+ [{"step": "\u6B65\u9AA4\u63CF\u8FF0", "tool": "\u5DE5\u5177\u540D", "input": {"\u53C2\u6570": "\u503C"}}]
200
+
201
+ \u4EFB\u52A1: ${task}
202
+
203
+ \u53EF\u7528\u5DE5\u5177: ${tools.map(t => t.name).join(", ")}`;
204
+ const planResponse = await llm(planPrompt);
205
+ try {
206
+ const parsed = JSON.parse(planResponse.replace(/```json|```/g, "").trim());
207
+ plans.value = parsed.map((p, i) => ({
208
+ id: `plan-${i}`,
209
+ description: p.step,
210
+ status: "pending"
211
+ }));
212
+ } catch {
213
+ plans.value = [{
214
+ id: "plan-0",
215
+ description: planResponse,
216
+ status: "pending"
217
+ }];
218
+ }
219
+ for (const plan of plans.value) {
220
+ currentPlan.value = plan.id;
221
+ plan.status = "pending";
222
+ try {
223
+ const execPrompt = `\u6839\u636E\u5F53\u524D\u6B65\u9AA4\u751F\u6210\u5DE5\u5177\u8C03\u7528\uFF1A
224
+
225
+ \u6B65\u9AA4: ${plan.description}
226
+ \u4E0A\u4E0B\u6587: ${JSON.stringify(results.value)}
227
+
228
+ \u8FD4\u56DE\u683C\u5F0F: {"tool": "\u5DE5\u5177\u540D", "input": {"\u53C2\u6570": "\u503C"}}`;
229
+ const execResponse = await llm(execPrompt);
230
+ const exec = JSON.parse(execResponse.replace(/```json|```/g, "").trim());
231
+ if (exec.tool) {
232
+ const result = await executeTool(exec.tool, exec.input || {});
233
+ results.value[plan.id] = result;
234
+ plan.status = "completed";
235
+ } else {
236
+ results.value[plan.id] = execResponse;
237
+ plan.status = "completed";
238
+ }
239
+ } catch (error) {
240
+ plan.status = "failed";
241
+ results.value[plan.id] = {
242
+ error: error instanceof Error ? error.message : String(error)
243
+ };
244
+ }
245
+ }
246
+ const summaryPrompt = `\u6839\u636E\u4EE5\u4E0B\u6267\u884C\u7ED3\u679C\uFF0C\u7528\u81EA\u7136\u8BED\u8A00\u603B\u7ED3\u56DE\u7B54\u7528\u6237\uFF1A
247
+
248
+ \u4EFB\u52A1: ${task}
249
+ \u6267\u884C\u7ED3\u679C: ${JSON.stringify(results.value)}
250
+
251
+ \u8BF7\u7528\u4E2D\u6587\u56DE\u7B54\uFF1A`;
252
+ const finalResult = await llm(summaryPrompt);
253
+ return {
254
+ result: finalResult,
255
+ plan: plans.value,
256
+ results: results.value
257
+ };
258
+ };
259
+ return {
260
+ plans,
261
+ currentPlan,
262
+ results,
263
+ execute
264
+ };
265
+ }
266
+ function createMultiModalMessage(role, contents) {
267
+ return {
268
+ role,
269
+ content: contents
270
+ };
271
+ }
272
+ function createImageContent(source, value, mimeType) {
273
+ return {
274
+ type: "image",
275
+ ...(source === "url" ? {
276
+ url: value
277
+ } : {
278
+ base64: value
279
+ }),
280
+ mimeType: mimeType || (source === "base64" ? "image/png" : void 0)
281
+ };
282
+ }
283
+ function createImageUrlContent(url, detail) {
284
+ return {
285
+ type: "image_url",
286
+ url,
287
+ mimeType: detail
288
+ };
289
+ }
290
+ function createAudioContent(base64, mimeType = "audio/m4a") {
291
+ return {
292
+ type: "audio",
293
+ base64,
294
+ mimeType
295
+ };
296
+ }
297
+ function createVideoContent(base64, mimeType = "video/mp4") {
298
+ return {
299
+ type: "video",
300
+ base64,
301
+ mimeType
302
+ };
303
+ }
304
+ function createRAGSystem(config) {
305
+ const {
306
+ knowledgeBaseId,
307
+ topK = 3,
308
+ similarityThreshold = 0.5,
309
+ includeSources = true,
310
+ strategy = "similarity"
311
+ } = config;
312
+ const vectorStore = /* @__PURE__ */new Map();
313
+ const addDocuments = async documents => {
314
+ const chunks = documents.map((doc, i) => ({
315
+ id: `chunk-${Date.now()}-${i}`,
316
+ content: doc.content,
317
+ metadata: doc.metadata || {},
318
+ // 简化:实际应该调用 embedding API
319
+ score: Math.random()
320
+ }));
321
+ if (knowledgeBaseId) {
322
+ const existing = vectorStore.get(knowledgeBaseId) || [];
323
+ vectorStore.set(knowledgeBaseId, [...existing, ...chunks]);
324
+ }
325
+ return chunks;
326
+ };
327
+ const retrieve = async (query2, k = topK) => {
328
+ if (!knowledgeBaseId) return [];
329
+ const chunks = vectorStore.get(knowledgeBaseId) || [];
330
+ const sorted = [...chunks].sort((a, b) => (b.score || 0) - (a.score || 0)).slice(0, k);
331
+ return sorted.filter(c => (c.score || 0) >= similarityThreshold);
332
+ };
333
+ const query = async (question, llm) => {
334
+ const relevantDocs = await retrieve(question);
335
+ if (relevantDocs.length === 0) {
336
+ return {
337
+ answer: "\u62B1\u6B49\uFF0C\u77E5\u8BC6\u5E93\u4E2D\u6CA1\u6709\u627E\u5230\u76F8\u5173\u4FE1\u606F\u3002",
338
+ sources: [],
339
+ contextUsed: ""
340
+ };
341
+ }
342
+ const context = relevantDocs.map((doc, i) => `[\u6587\u6863 ${i + 1}]
343
+ ${doc.content}`).join("\n\n");
344
+ const prompt = `\u57FA\u4E8E\u4EE5\u4E0B\u77E5\u8BC6\u5E93\u5185\u5BB9\uFF0C\u7528\u4E2D\u6587\u56DE\u7B54\u7528\u6237\u7684\u95EE\u9898\u3002\u5982\u679C\u77E5\u8BC6\u5E93\u4E2D\u7684\u4FE1\u606F\u4E0D\u80FD\u56DE\u7B54\u95EE\u9898\uFF0C\u8BF7\u8BF4\u660E\u3002
345
+
346
+ \u77E5\u8BC6\u5E93\u5185\u5BB9:
347
+ ${context}
348
+
349
+ \u7528\u6237\u95EE\u9898: ${question}
350
+
351
+ \u8BF7\u7ED9\u51FA\u56DE\u7B54\uFF1A`;
352
+ const answer = await llm(prompt);
353
+ return {
354
+ answer,
355
+ sources: includeSources ? relevantDocs.map(doc => ({
356
+ content: doc.content.slice(0, 200) + "...",
357
+ metadata: doc.metadata,
358
+ score: doc.score || 0
359
+ })) : [],
360
+ contextUsed: context.slice(0, 500)
361
+ };
362
+ };
363
+ const clear = () => {
364
+ if (knowledgeBaseId) {
365
+ vectorStore.delete(knowledgeBaseId);
366
+ }
367
+ };
368
+ return {
369
+ addDocuments,
370
+ retrieve,
371
+ query,
372
+ clear,
373
+ config: {
374
+ topK,
375
+ similarityThreshold,
376
+ strategy
377
+ }
378
+ };
379
+ }
380
+ function createChainOfThought(config = {
381
+ mode: "standard"
382
+ }) {
383
+ const {
384
+ mode = "standard",
385
+ maxDepth = 5,
386
+ showConfidence = false
387
+ } = config;
388
+ const reasoningSteps = (0, _vue.ref)([]);
389
+ const think = async (problem, llm) => {
390
+ reasoningSteps.value = [];
391
+ const prompt = mode === "standard" ? `\u9010\u6B65\u601D\u8003\u5E76\u7ED9\u51FA\u7B54\u6848\uFF1A${problem}` : mode === "chain" ? `\u6309\u6B65\u9AA4\u5206\u6790\uFF1A${problem}` : mode === "tree" ? `\u7528\u6811\u72B6\u7ED3\u6784\u5206\u6790\uFF1A${problem}` : `\u7528\u8868\u683C\u5F62\u5F0F\u5206\u6790\uFF1A${problem}`;
392
+ const response = await llm(prompt);
393
+ const lines = response.split("\n").filter(l => l.trim());
394
+ reasoningSteps.value = lines.map((line, i) => ({
395
+ id: `reason-${i}`,
396
+ content: line.replace(/^\d+[.)::、]\s*/, ""),
397
+ type: i === lines.length - 1 ? "conclusion" : "analysis"
398
+ }));
399
+ return {
400
+ result: response,
401
+ reasoning: reasoningSteps.value
402
+ };
403
+ };
404
+ const addStep = step => {
405
+ reasoningSteps.value.push({
406
+ ...step,
407
+ id: `reason-${Date.now()}-${Math.random().toString(36).slice(2)}`
408
+ });
409
+ };
410
+ const clear = () => {
411
+ reasoningSteps.value = [];
412
+ };
413
+ return {
414
+ think,
415
+ addStep,
416
+ clear,
417
+ reasoningSteps,
418
+ config: {
419
+ mode,
420
+ maxDepth,
421
+ showConfidence
422
+ }
423
+ };
424
+ }
425
+ function createContextCompressor(config) {
426
+ const {
427
+ strategy = "summary",
428
+ targetTokens = 2e3,
429
+ preserveKeyInfo = []
430
+ } = config;
431
+ const estimateTokens = text => Math.ceil(text.length / 4);
432
+ const compress = async (content, llm) => {
433
+ const isArray = Array.isArray(content);
434
+ const text = isArray ? content.map(m => `${m.role}: ${m.content}`).join("\n") : content;
435
+ const originalTokens = estimateTokens(text);
436
+ if (originalTokens <= targetTokens) {
437
+ return {
438
+ compressedContent: text,
439
+ originalTokens,
440
+ compressedTokens: originalTokens,
441
+ compressionRatio: 1,
442
+ extractedKeyInfo: preserveKeyInfo
443
+ };
444
+ }
445
+ let compressed;
446
+ switch (strategy) {
447
+ case "summary":
448
+ {
449
+ if (!llm) {
450
+ const ratio = targetTokens / originalTokens;
451
+ compressed = text.slice(0, Math.floor(text.length * ratio));
452
+ } else {
453
+ const summaryPrompt = `\u5C06\u4EE5\u4E0B\u5185\u5BB9\u538B\u7F29\u5230\u7EA6 ${targetTokens} \u5B57\u7B26\uFF0C\u4FDD\u7559\u5173\u952E\u4FE1\u606F\uFF1A
454
+
455
+ ${text}`;
456
+ compressed = await llm(summaryPrompt);
457
+ }
458
+ break;
459
+ }
460
+ case "extract":
461
+ {
462
+ const sentences = text.split(/[。!?\n]/).filter(s => s.trim());
463
+ const keySentences = sentences.slice(0, Math.floor(sentences.length * (targetTokens / originalTokens)));
464
+ compressed = keySentences.join("\u3002") + "\u3002";
465
+ break;
466
+ }
467
+ case "prune":
468
+ {
469
+ const lines = text.split("\n");
470
+ const seen = /* @__PURE__ */new Set();
471
+ const pruned = lines.filter(line => {
472
+ const key = line.slice(0, 50);
473
+ if (seen.has(key)) return false;
474
+ seen.add(key);
475
+ return true;
476
+ });
477
+ compressed = pruned.join("\n").slice(0, targetTokens * 4);
478
+ break;
479
+ }
480
+ default:
481
+ compressed = text.slice(0, targetTokens * 4);
482
+ }
483
+ const compressedTokens = estimateTokens(compressed);
484
+ return {
485
+ compressedContent: compressed,
486
+ originalTokens,
487
+ compressedTokens,
488
+ compressionRatio: compressedTokens / originalTokens,
489
+ extractedKeyInfo: preserveKeyInfo
490
+ };
491
+ };
492
+ return {
493
+ compress,
494
+ estimateTokens,
495
+ config: {
496
+ strategy,
497
+ targetTokens,
498
+ preserveKeyInfo
499
+ }
500
+ };
501
+ }
502
+ function createCostTracker(config = {}) {
503
+ const {
504
+ monthlyBudget = 100,
505
+ maxTokensPerRequest = 1e5,
506
+ warningThreshold = 0.8
507
+ } = config;
508
+ const dailyUsage = {};
509
+ const totalUsage = {
510
+ prompt: 0,
511
+ completion: 0,
512
+ total: 0
513
+ };
514
+ const PRICING = {
515
+ "gpt-4": {
516
+ prompt: 30,
517
+ completion: 60
518
+ },
519
+ "gpt-4-turbo": {
520
+ prompt: 10,
521
+ completion: 30
522
+ },
523
+ "gpt-3.5-turbo": {
524
+ prompt: 0.5,
525
+ completion: 1.5
526
+ },
527
+ "claude-3-opus": {
528
+ prompt: 15,
529
+ completion: 75
530
+ },
531
+ "claude-3-sonnet": {
532
+ prompt: 3,
533
+ completion: 15
534
+ },
535
+ "gemini-pro": {
536
+ prompt: 0.5,
537
+ completion: 1.5
538
+ }
539
+ };
540
+ const track = (usage, _model = "gpt-4") => {
541
+ const today = (/* @__PURE__ */new Date()).toISOString().split("T")[0];
542
+ if (!dailyUsage[today]) {
543
+ dailyUsage[today] = {
544
+ prompt: 0,
545
+ completion: 0
546
+ };
547
+ }
548
+ dailyUsage[today].prompt += usage.prompt;
549
+ dailyUsage[today].completion += usage.completion;
550
+ totalUsage.prompt += usage.prompt;
551
+ totalUsage.completion += usage.completion;
552
+ totalUsage.total += usage.prompt + usage.completion;
553
+ };
554
+ const calculateCost = (usage, model) => {
555
+ const pricing = PRICING[model] || PRICING["gpt-4"];
556
+ return pricing.prompt * usage.prompt / 1e6 + pricing.completion * usage.completion / 1e6;
557
+ };
558
+ const getStatus = () => {
559
+ const totalCost = calculateCost(totalUsage, "gpt-4");
560
+ const budgetRemaining = monthlyBudget - totalCost;
561
+ return {
562
+ totalCost,
563
+ dailyCost: Object.fromEntries(Object.entries(dailyUsage).map(([date, usage]) => [date, calculateCost({
564
+ prompt: usage.prompt,
565
+ completion: usage.completion,
566
+ total: 0
567
+ }, "gpt-4")])),
568
+ usage: {
569
+ ...totalUsage
570
+ },
571
+ budget: {
572
+ monthlyBudget,
573
+ warningThreshold
574
+ },
575
+ remaining: budgetRemaining
576
+ };
577
+ };
578
+ const isOverBudget = () => {
579
+ const status = getStatus();
580
+ return status.remaining < 0;
581
+ };
582
+ const shouldWarn = () => {
583
+ const status = getStatus();
584
+ return status.totalCost >= monthlyBudget * warningThreshold;
585
+ };
586
+ const checkRequestLimit = tokens => {
587
+ if (tokens > maxTokensPerRequest) {
588
+ return {
589
+ allowed: false,
590
+ reason: `\u8BF7\u6C42 token \u6570 ${tokens} \u8D85\u8FC7\u9650\u5236 ${maxTokensPerRequest}`
591
+ };
592
+ }
593
+ const status = getStatus();
594
+ const estimatedCost = tokens / 1e6 * 30;
595
+ if (status.remaining - estimatedCost < 0) {
596
+ return {
597
+ allowed: false,
598
+ reason: "\u9884\u7B97\u4E0D\u8DB3"
599
+ };
600
+ }
601
+ return {
602
+ allowed: true
603
+ };
604
+ };
605
+ const reset = () => {
606
+ Object.keys(dailyUsage).forEach(key => delete dailyUsage[key]);
607
+ totalUsage.prompt = 0;
608
+ totalUsage.completion = 0;
609
+ totalUsage.total = 0;
610
+ };
611
+ return {
612
+ track,
613
+ calculateCost,
614
+ getStatus,
615
+ isOverBudget,
616
+ shouldWarn,
617
+ checkRequestLimit,
618
+ reset,
619
+ pricing: PRICING,
620
+ config: {
621
+ monthlyBudget,
622
+ maxTokensPerRequest,
623
+ warningThreshold
624
+ }
625
+ };
626
+ }
627
+ function createTracer() {
628
+ const spans = (0, _vue.ref)([]);
629
+ const events = (0, _vue.ref)([]);
630
+ const activeSpans = /* @__PURE__ */new Map();
631
+ const startSpan = (name, attributes = {}) => {
632
+ const id = `span-${Date.now()}-${Math.random().toString(36).slice(2)}`;
633
+ const span = {
634
+ id,
635
+ name,
636
+ startTime: /* @__PURE__ */new Date(),
637
+ events: [],
638
+ attributes,
639
+ children: []
640
+ };
641
+ spans.value.push(span);
642
+ activeSpans.set(id, span);
643
+ addEvent({
644
+ type: "custom",
645
+ data: {
646
+ action: "span_start",
647
+ name
648
+ }
649
+ });
650
+ return id;
651
+ };
652
+ const endSpan = (id, attributes = {}) => {
653
+ const span = activeSpans.get(id);
654
+ if (span) {
655
+ span.endTime = /* @__PURE__ */new Date();
656
+ span.attributes = {
657
+ ...span.attributes,
658
+ ...attributes
659
+ };
660
+ activeSpans.delete(id);
661
+ addEvent({
662
+ type: "custom",
663
+ data: {
664
+ action: "span_end",
665
+ name: span.name,
666
+ duration: span.endTime.getTime() - span.startTime.getTime()
667
+ }
668
+ });
669
+ }
670
+ };
671
+ const addEvent = event => {
672
+ events.value.push({
673
+ ...event,
674
+ id: `event-${Date.now()}-${Math.random().toString(36).slice(2)}`,
675
+ timestamp: /* @__PURE__ */new Date()
676
+ });
677
+ };
678
+ const recordRequest = (config, spanId) => {
679
+ const event = {
680
+ id: `req-${Date.now()}`,
681
+ type: "request",
682
+ timestamp: /* @__PURE__ */new Date(),
683
+ data: config,
684
+ parentId: spanId
685
+ };
686
+ events.value.push(event);
687
+ };
688
+ const recordResponse = (response, duration, spanId) => {
689
+ const event = {
690
+ id: `res-${Date.now()}`,
691
+ type: "response",
692
+ timestamp: /* @__PURE__ */new Date(),
693
+ data: {
694
+ response,
695
+ duration
696
+ },
697
+ parentId: spanId
698
+ };
699
+ events.value.push(event);
700
+ };
701
+ const recordError = (error, context, spanId) => {
702
+ const event = {
703
+ id: `err-${Date.now()}`,
704
+ type: "error",
705
+ timestamp: /* @__PURE__ */new Date(),
706
+ data: {
707
+ message: error.message,
708
+ stack: error.stack,
709
+ ...context
710
+ },
711
+ parentId: spanId
712
+ };
713
+ events.value.push(event);
714
+ };
715
+ const getEvents = () => events.value;
716
+ const getSpans = () => spans.value;
717
+ const clear = () => {
718
+ spans.value = [];
719
+ events.value = [];
720
+ activeSpans.clear();
721
+ };
722
+ const exportJSON = () => JSON.stringify({
723
+ spans: spans.value,
724
+ events: events.value
725
+ }, null, 2);
726
+ return {
727
+ startSpan,
728
+ endSpan,
729
+ addEvent,
730
+ recordRequest,
731
+ recordResponse,
732
+ recordError,
733
+ getEvents,
734
+ getSpans,
735
+ clear,
736
+ exportJSON
737
+ };
738
+ }
739
+ function createSafetyFilter(config) {
740
+ const {
741
+ rules = []
742
+ } = config;
743
+ const check = async content => {
744
+ const violations = [];
745
+ for (const rule of rules) {
746
+ let passed = true;
747
+ let replacedContent = content;
748
+ if (rule.pattern) {
749
+ const regex = typeof rule.pattern === "string" ? new RegExp(rule.pattern, "gi") : rule.pattern;
750
+ passed = !regex.test(content);
751
+ replacedContent = content.replace(regex, "***");
752
+ }
753
+ if (rule.customCheck && passed) {
754
+ passed = !(await rule.customCheck(content));
755
+ }
756
+ if (!passed) {
757
+ violations.push({
758
+ rule,
759
+ content,
760
+ action: rule.action === "replace" && replacedContent !== content ? "replaced" : rule.action === "block" ? "blocked" : "warned",
761
+ replacedContent: rule.action === "replace" ? replacedContent : void 0
762
+ });
763
+ if (rule.action === "block") {
764
+ break;
765
+ }
766
+ }
767
+ }
768
+ return {
769
+ passed: violations.length === 0 || violations.every(v => v.action !== "blocked"),
770
+ violations
771
+ };
772
+ };
773
+ const addRule = rule => {
774
+ rules.push(rule);
775
+ };
776
+ const removeRule = ruleId => {
777
+ const index = rules.findIndex(r => r.id === ruleId);
778
+ if (index > -1) {
779
+ rules.splice(index, 1);
780
+ }
781
+ };
782
+ const createPresetRules = type => {
783
+ const presets = {
784
+ strict: [{
785
+ id: "s1",
786
+ name: "\u653F\u6CBB\u654F\u611F",
787
+ type: "content_filter",
788
+ pattern: "\u653F\u6CBB|\u9886\u5BFC\u4EBA",
789
+ action: "block"
790
+ }, {
791
+ id: "s2",
792
+ name: "\u66B4\u529B\u5185\u5BB9",
793
+ type: "content_filter",
794
+ pattern: "\u66B4\u529B|\u8840\u8165",
795
+ action: "block"
796
+ }, {
797
+ id: "s3",
798
+ name: "\u6076\u610F\u8F6F\u4EF6",
799
+ type: "content_filter",
800
+ pattern: "\u75C5\u6BD2|\u6728\u9A6C",
801
+ action: "block"
802
+ }],
803
+ moderate: [{
804
+ id: "m1",
805
+ name: "\u653F\u6CBB\u654F\u611F",
806
+ type: "content_filter",
807
+ pattern: "\u653F\u6CBB|\u9886\u5BFC\u4EBA",
808
+ action: "warn"
809
+ }, {
810
+ id: "m2",
811
+ name: "\u66B4\u529B\u5185\u5BB9",
812
+ type: "content_filter",
813
+ pattern: "\u66B4\u529B|\u8840\u8165",
814
+ action: "warn"
815
+ }],
816
+ lenient: [{
817
+ id: "l1",
818
+ name: "\u6076\u610F\u5185\u5BB9",
819
+ type: "content_filter",
820
+ pattern: "\u75C5\u6BD2|\u6728\u9A6C",
821
+ action: "block"
822
+ }]
823
+ };
824
+ rules.push(...presets[type]);
825
+ };
826
+ return {
827
+ check,
828
+ addRule,
829
+ removeRule,
830
+ createPresetRules,
831
+ rules
832
+ };
833
+ }
834
+ function fromZodSchema(schema2) {
835
+ return {
836
+ type: "object",
837
+ schema: schema2,
838
+ toJSONSchema: () => schema2
839
+ };
840
+ }
841
+ function createJSONSchema(definition) {
842
+ return definition;
843
+ }
844
+ const schema = exports.schema = {
845
+ string: description => ({
846
+ type: "string",
847
+ description
848
+ }),
849
+ number: description => ({
850
+ type: "number",
851
+ description
852
+ }),
853
+ boolean: description => ({
854
+ type: "boolean",
855
+ description
856
+ }),
857
+ enum: (values, description) => ({
858
+ type: "string",
859
+ enum: values,
860
+ description
861
+ }),
862
+ array: items => ({
863
+ type: "array",
864
+ items
865
+ }),
866
+ object: (properties, required = []) => ({
867
+ type: "object",
868
+ properties,
869
+ required
870
+ })
871
+ };
872
+ function parseStructuredOutput(output, _schema) {
873
+ try {
874
+ const jsonMatch = output.match(/\{[\s\S]*\}/);
875
+ if (jsonMatch) {
876
+ return JSON.parse(jsonMatch[0]);
877
+ }
878
+ } catch {
879
+ return null;
880
+ }
881
+ return null;
882
+ }