@shwfed/config 1.0.0 → 1.1.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/README.md +1 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +169 -23
- package/dist/runtime/components/config/footer.vue +0 -2
- package/dist/runtime/components/config/index.vue +13 -3
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue +85 -10
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue +85 -10
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue +87 -11
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.vue +3 -0
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/runtime.vue +8 -0
- package/dist/runtime/components/form/index.vue +2 -2
- package/dist/runtime/components/table/ai/columns-button.vue +91 -98
- package/dist/runtime/components/table/ai/data-source-button.vue +88 -95
- package/dist/runtime/components/table/index.vue +5 -7
- package/dist/runtime/plugins/ai/index.d.ts +1 -5
- package/dist/runtime/plugins/ai/index.js +185 -441
- package/dist/runtime/plugins/cel/index.js +7 -0
- package/dist/runtime/vendor/cel-js/PROMPT.md +8 -0
- package/package.json +4 -4
- package/dist/chunks/index.mjs +0 -212742
- package/dist/runtime/components/ai/byok-button.d.vue.ts +0 -3
- package/dist/runtime/components/ai/byok-button.vue +0 -48
- package/dist/runtime/components/ai/byok-button.vue.d.ts +0 -3
- package/dist/runtime/components/ai/byok-settings.d.vue.ts +0 -3
- package/dist/runtime/components/ai/byok-settings.vue +0 -282
- package/dist/runtime/components/ai/byok-settings.vue.d.ts +0 -3
- package/dist/runtime/plugins/ai/gate.d.ts +0 -1
- package/dist/runtime/plugins/ai/gate.js +0 -8
- package/dist/runtime/plugins/ai/settings-state.d.ts +0 -1
- package/dist/runtime/plugins/ai/settings-state.js +0 -2
- package/dist/runtime/plugins/ai/store.d.ts +0 -17
- package/dist/runtime/plugins/ai/store.js +0 -40
- package/dist/shared/config.DW2OtAXe.mjs +0 -86529
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { defineNuxtPlugin } from "#app";
|
|
2
2
|
import { computed } from "vue";
|
|
3
3
|
import { JSONSchema, Schema } from "effect";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const DEFAULT_ANTHROPIC_ENDPOINT = "https://api.anthropic.com/v1/messages";
|
|
9
|
-
const DEFAULT_OPENAI_MODEL = "gpt-4o-mini";
|
|
10
|
-
const DEFAULT_OPENAI_ENDPOINT = "https://api.openai.com/v1/chat/completions";
|
|
4
|
+
const ENDPOINT = "http://192.168.168.10/anthropic/v1/messages";
|
|
5
|
+
const MODEL = "MiniMax-M2.7";
|
|
6
|
+
const ANTHROPIC_VERSION = "2023-06-01";
|
|
7
|
+
const DEFAULT_MAX_TOKENS = 8192;
|
|
11
8
|
export class StructuredOutputDecodeError extends Error {
|
|
12
9
|
rawOutput;
|
|
13
10
|
constructor(rawOutput, cause) {
|
|
@@ -51,467 +48,214 @@ async function* readSSE(res) {
|
|
|
51
48
|
}
|
|
52
49
|
}
|
|
53
50
|
}
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
messages.push({
|
|
82
|
-
role: "user",
|
|
83
|
-
content: [{
|
|
84
|
-
type: "tool_result",
|
|
85
|
-
tool_use_id: RETRY_TOOL_USE_ID,
|
|
86
|
-
content: retry.feedback
|
|
87
|
-
}]
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
return messages;
|
|
91
|
-
}
|
|
92
|
-
function buildInit(body, signal) {
|
|
93
|
-
return {
|
|
94
|
-
method: "POST",
|
|
95
|
-
headers: {
|
|
96
|
-
"content-type": "application/json",
|
|
97
|
-
"x-api-key": cfg.apiKey,
|
|
98
|
-
"anthropic-version": "2023-06-01",
|
|
99
|
-
// CORS opt-in for browser-direct calls. The name is deliberately
|
|
100
|
-
// scary — keys live in localStorage on dev/beta only, gated by gate.ts.
|
|
101
|
-
"anthropic-dangerous-direct-browser-access": "true"
|
|
102
|
-
},
|
|
103
|
-
body: JSON.stringify(body),
|
|
104
|
-
...signal ? { signal } : {}
|
|
105
|
-
};
|
|
51
|
+
function buildBody(messages, system, options) {
|
|
52
|
+
return {
|
|
53
|
+
model: MODEL,
|
|
54
|
+
messages,
|
|
55
|
+
max_tokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
56
|
+
...system !== void 0 ? { system } : {},
|
|
57
|
+
...options.tools !== void 0 ? { tools: options.tools } : {},
|
|
58
|
+
...options.toolChoice !== void 0 ? { tool_choice: options.toolChoice } : {}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function buildInit(body, signal) {
|
|
62
|
+
return {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: {
|
|
65
|
+
"content-type": "application/json",
|
|
66
|
+
"anthropic-version": ANTHROPIC_VERSION,
|
|
67
|
+
"anthropic-dangerous-direct-browser-access": "true"
|
|
68
|
+
},
|
|
69
|
+
body: JSON.stringify(body),
|
|
70
|
+
...signal ? { signal } : {}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async function call(messages, system, options, signal) {
|
|
74
|
+
const res = await fetch(ENDPOINT, buildInit(buildBody(messages, system, options), signal));
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
throw new Error(`Anthropic ${res.status}: ${await readError(res) || res.statusText}`);
|
|
106
77
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
78
|
+
return await res.json();
|
|
79
|
+
}
|
|
80
|
+
async function callStream(messages, system, options, signal, onProgress) {
|
|
81
|
+
const body = { ...buildBody(messages, system, options), stream: true };
|
|
82
|
+
const res = await fetch(ENDPOINT, buildInit(body, signal));
|
|
83
|
+
if (!res.ok) {
|
|
84
|
+
throw new Error(`Anthropic ${res.status}: ${await readError(res) || res.statusText}`);
|
|
113
85
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (!
|
|
118
|
-
|
|
86
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
87
|
+
let stopReason;
|
|
88
|
+
for await (const ev of readSSE(res)) {
|
|
89
|
+
if (!ev.event || !ev.data) continue;
|
|
90
|
+
let payload;
|
|
91
|
+
try {
|
|
92
|
+
payload = JSON.parse(ev.data);
|
|
93
|
+
} catch {
|
|
94
|
+
continue;
|
|
119
95
|
}
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
block.inputJson += data.delta.partial_json;
|
|
140
|
-
onProgress();
|
|
141
|
-
}
|
|
96
|
+
const p = payload;
|
|
97
|
+
if (p.type === "content_block_start" && typeof p.index === "number" && p.content_block) {
|
|
98
|
+
const cb = p.content_block;
|
|
99
|
+
blocks.set(p.index, {
|
|
100
|
+
type: cb.type === "tool_use" ? "tool_use" : "text",
|
|
101
|
+
text: "",
|
|
102
|
+
toolId: cb.id,
|
|
103
|
+
toolName: cb.name,
|
|
104
|
+
inputJson: ""
|
|
105
|
+
});
|
|
106
|
+
} else if (p.type === "content_block_delta" && typeof p.index === "number" && p.delta) {
|
|
107
|
+
const cur = blocks.get(p.index);
|
|
108
|
+
if (!cur) continue;
|
|
109
|
+
if (p.delta.type === "text_delta" && p.delta.text) {
|
|
110
|
+
cur.text += p.delta.text;
|
|
111
|
+
onProgress();
|
|
112
|
+
} else if (p.delta.type === "input_json_delta" && p.delta.partial_json) {
|
|
113
|
+
cur.inputJson += p.delta.partial_json;
|
|
114
|
+
onProgress();
|
|
142
115
|
}
|
|
116
|
+
} else if (p.type === "message_delta" && p.delta?.stop_reason) {
|
|
117
|
+
stopReason = p.delta.stop_reason;
|
|
118
|
+
} else if (p.type === "message_stop") {
|
|
119
|
+
break;
|
|
143
120
|
}
|
|
144
|
-
const ordered = [...blocks.entries()].sort(([a], [b]) => a - b);
|
|
145
|
-
const content = ordered.map(([, block]) => {
|
|
146
|
-
if (block.type === "text") return { type: "text", text: block.text };
|
|
147
|
-
if (block.type === "tool_use") {
|
|
148
|
-
let input = {};
|
|
149
|
-
if (block.inputJson) {
|
|
150
|
-
try {
|
|
151
|
-
input = JSON.parse(block.inputJson);
|
|
152
|
-
} catch {
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return {
|
|
156
|
-
type: "tool_use",
|
|
157
|
-
id: block.id ?? "",
|
|
158
|
-
name: block.name ?? "",
|
|
159
|
-
input
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
return { type: block.type };
|
|
163
|
-
});
|
|
164
|
-
return { content };
|
|
165
121
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
async generateText(input) {
|
|
171
|
-
const opts = {
|
|
172
|
-
...input.system !== void 0 ? { system: input.system } : {},
|
|
173
|
-
...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {}
|
|
174
|
-
};
|
|
175
|
-
const messages = [{ role: "user", content: input.prompt }];
|
|
176
|
-
const response = input.onProgress ? await callStream(messages, opts, input.signal, input.onProgress) : await call(messages, opts, input.signal);
|
|
177
|
-
return extractText(response);
|
|
178
|
-
},
|
|
179
|
-
async generateObject(input) {
|
|
180
|
-
const toolName = input.objectName ?? "structured_output";
|
|
181
|
-
const structuredSchema = JSONSchema.make(input.schema);
|
|
182
|
-
const helperTools = input.tools ?? [];
|
|
183
|
-
const helperByName = new Map(helperTools.map((t) => [t.name, t]));
|
|
184
|
-
const tools = [
|
|
185
|
-
...helperTools.map((t) => ({
|
|
186
|
-
name: t.name,
|
|
187
|
-
description: t.description,
|
|
188
|
-
input_schema: t.inputJsonSchema
|
|
189
|
-
})),
|
|
190
|
-
{
|
|
191
|
-
name: toolName,
|
|
192
|
-
description: "Return the structured output as the tool input.",
|
|
193
|
-
input_schema: structuredSchema
|
|
194
|
-
}
|
|
195
|
-
];
|
|
196
|
-
const toolChoice = helperTools.length > 0 ? { type: "any" } : { type: "tool", name: toolName };
|
|
197
|
-
const optsBase = {
|
|
198
|
-
...input.system !== void 0 ? { system: input.system } : {},
|
|
199
|
-
...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {},
|
|
200
|
-
tools,
|
|
201
|
-
toolChoice
|
|
202
|
-
};
|
|
203
|
-
const messages = buildInitialMessages(
|
|
204
|
-
input.prompt,
|
|
205
|
-
input.retry !== void 0 ? { ...input.retry, toolName } : void 0
|
|
206
|
-
);
|
|
207
|
-
const decode = (raw) => {
|
|
122
|
+
const content = [...blocks.entries()].sort(([a], [b]) => a - b).map(([, v]) => {
|
|
123
|
+
if (v.type === "tool_use") {
|
|
124
|
+
let input = {};
|
|
125
|
+
if (v.inputJson) {
|
|
208
126
|
try {
|
|
209
|
-
|
|
210
|
-
} catch
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
for (; ; ) {
|
|
215
|
-
const response = input.onProgress ? await callStream(messages, optsBase, input.signal, input.onProgress) : await call(messages, optsBase, input.signal);
|
|
216
|
-
const structured = response.content.find(
|
|
217
|
-
(b) => b.type === "tool_use" && b.name === toolName
|
|
218
|
-
);
|
|
219
|
-
if (structured) return decode(structured.input);
|
|
220
|
-
const helperCalls = response.content.filter(
|
|
221
|
-
(b) => b.type === "tool_use"
|
|
222
|
-
);
|
|
223
|
-
if (helperCalls.length === 0) {
|
|
224
|
-
const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
225
|
-
throw new Error(`\u6A21\u578B\u672A\u8FD4\u56DE\u7ED3\u6784\u5316\u8F93\u51FA${text ? `: ${text.slice(0, 200)}` : ""}`);
|
|
226
|
-
}
|
|
227
|
-
const toolResults = [];
|
|
228
|
-
for (const callBlock of helperCalls) {
|
|
229
|
-
const tool = helperByName.get(callBlock.name);
|
|
230
|
-
if (!tool) {
|
|
231
|
-
toolResults.push({
|
|
232
|
-
type: "tool_result",
|
|
233
|
-
tool_use_id: callBlock.id,
|
|
234
|
-
content: `Unknown tool: ${callBlock.name}`,
|
|
235
|
-
is_error: true
|
|
236
|
-
});
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
try {
|
|
240
|
-
const result = await tool.execute(callBlock.input);
|
|
241
|
-
toolResults.push({
|
|
242
|
-
type: "tool_result",
|
|
243
|
-
tool_use_id: callBlock.id,
|
|
244
|
-
content: typeof result === "string" ? result : JSON.stringify(result)
|
|
245
|
-
});
|
|
246
|
-
} catch (err) {
|
|
247
|
-
toolResults.push({
|
|
248
|
-
type: "tool_result",
|
|
249
|
-
tool_use_id: callBlock.id,
|
|
250
|
-
content: err instanceof Error ? err.message : String(err),
|
|
251
|
-
is_error: true
|
|
252
|
-
});
|
|
253
|
-
}
|
|
127
|
+
input = JSON.parse(v.inputJson);
|
|
128
|
+
} catch {
|
|
129
|
+
input = {};
|
|
254
130
|
}
|
|
255
|
-
messages.push({ role: "assistant", content: response.content });
|
|
256
|
-
messages.push({ role: "user", content: toolResults });
|
|
257
131
|
}
|
|
132
|
+
return {
|
|
133
|
+
type: "tool_use",
|
|
134
|
+
id: v.toolId ?? "",
|
|
135
|
+
name: v.toolName ?? "",
|
|
136
|
+
input
|
|
137
|
+
};
|
|
258
138
|
}
|
|
259
|
-
|
|
139
|
+
return { type: "text", text: v.text };
|
|
140
|
+
});
|
|
141
|
+
return { content, stop_reason: stopReason };
|
|
260
142
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
143
|
+
const RETRY_TOOL_USE_ID = "retry_call_0";
|
|
144
|
+
function buildUserMessages(prompt) {
|
|
145
|
+
return [{ role: "user", content: prompt }];
|
|
146
|
+
}
|
|
147
|
+
function appendRetry(messages, retry, toolName) {
|
|
148
|
+
messages.push({
|
|
149
|
+
role: "assistant",
|
|
150
|
+
content: [{
|
|
151
|
+
type: "tool_use",
|
|
152
|
+
id: RETRY_TOOL_USE_ID,
|
|
153
|
+
name: toolName,
|
|
154
|
+
input: retry.previousOutput
|
|
155
|
+
}]
|
|
156
|
+
});
|
|
157
|
+
messages.push({
|
|
158
|
+
role: "user",
|
|
159
|
+
content: [{
|
|
160
|
+
type: "tool_result",
|
|
161
|
+
tool_use_id: RETRY_TOOL_USE_ID,
|
|
162
|
+
content: retry.feedback
|
|
163
|
+
}]
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
async function generateText(input) {
|
|
167
|
+
const messages = buildUserMessages(input.prompt);
|
|
168
|
+
const opts = input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {};
|
|
169
|
+
const response = input.onProgress ? await callStream(messages, input.system, opts, input.signal, input.onProgress) : await call(messages, input.system, opts, input.signal);
|
|
170
|
+
return response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
171
|
+
}
|
|
172
|
+
async function generateObject(input) {
|
|
173
|
+
const toolName = input.objectName ?? "structured_output";
|
|
174
|
+
const structuredParams = JSONSchema.make(input.schema);
|
|
175
|
+
const helperTools = input.tools ?? [];
|
|
176
|
+
const helperByName = new Map(helperTools.map((t) => [t.name, t]));
|
|
177
|
+
const tools = [
|
|
178
|
+
...helperTools.map((t) => ({
|
|
179
|
+
name: t.name,
|
|
180
|
+
description: t.description,
|
|
181
|
+
input_schema: t.inputJsonSchema
|
|
182
|
+
})),
|
|
183
|
+
{
|
|
184
|
+
name: toolName,
|
|
185
|
+
description: "Return the structured output as the tool input.",
|
|
186
|
+
input_schema: structuredParams
|
|
289
187
|
}
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
188
|
+
];
|
|
189
|
+
const toolChoice = helperTools.length > 0 ? { type: "any" } : { type: "tool", name: toolName };
|
|
190
|
+
const messages = buildUserMessages(input.prompt);
|
|
191
|
+
if (input.retry) appendRetry(messages, input.retry, toolName);
|
|
192
|
+
const opts = {
|
|
193
|
+
tools,
|
|
194
|
+
toolChoice,
|
|
195
|
+
...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {}
|
|
196
|
+
};
|
|
197
|
+
const decode = (raw) => {
|
|
198
|
+
try {
|
|
199
|
+
return Schema.decodeUnknownSync(input.schema)(raw);
|
|
200
|
+
} catch (cause) {
|
|
201
|
+
throw new StructuredOutputDecodeError(raw, cause);
|
|
297
202
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (choice.finish_reason) finishReason = choice.finish_reason;
|
|
312
|
-
const delta = choice.delta;
|
|
313
|
-
if (!delta) continue;
|
|
314
|
-
if (delta.content) {
|
|
315
|
-
content += delta.content;
|
|
316
|
-
onProgress();
|
|
317
|
-
}
|
|
318
|
-
if (delta.tool_calls) {
|
|
319
|
-
for (const tc of delta.tool_calls) {
|
|
320
|
-
const idx = tc.index ?? 0;
|
|
321
|
-
const cur = tools.get(idx) ?? { arguments: "" };
|
|
322
|
-
if (tc.id) cur.id = tc.id;
|
|
323
|
-
if (tc.function?.name) cur.name = tc.function.name;
|
|
324
|
-
if (tc.function?.arguments) {
|
|
325
|
-
cur.arguments += tc.function.arguments;
|
|
326
|
-
onProgress();
|
|
327
|
-
}
|
|
328
|
-
tools.set(idx, cur);
|
|
329
|
-
}
|
|
203
|
+
};
|
|
204
|
+
for (; ; ) {
|
|
205
|
+
const response = input.onProgress ? await callStream(messages, input.system, opts, input.signal, input.onProgress) : await call(messages, input.system, opts, input.signal);
|
|
206
|
+
const toolUses = response.content.filter(
|
|
207
|
+
(b) => b.type === "tool_use"
|
|
208
|
+
);
|
|
209
|
+
const structured = toolUses.find((c) => c.name === toolName);
|
|
210
|
+
if (structured) {
|
|
211
|
+
return decode(structured.input);
|
|
212
|
+
}
|
|
213
|
+
if (toolUses.length === 0) {
|
|
214
|
+
if (response.stop_reason === "max_tokens") {
|
|
215
|
+
throw new Error("\u6A21\u578B\u5728\u4EA7\u51FA\u7ED3\u6784\u5316\u7ED3\u679C\u524D\u7528\u5C3D\u4E86 token \u9884\u7B97\uFF08stop_reason=max_tokens\uFF09\u3002\u8BF7\u63D0\u9AD8 maxTokens\uFF0C\u6216\u6362\u7528\u975E\u63A8\u7406\u6A21\u578B\u3002");
|
|
330
216
|
}
|
|
217
|
+
const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
218
|
+
const reason = response.stop_reason ? `\uFF08stop_reason=${response.stop_reason}\uFF09` : "";
|
|
219
|
+
throw new Error(`\u6A21\u578B\u672A\u8FD4\u56DE\u7ED3\u6784\u5316\u8F93\u51FA${reason}${text ? `: ${text.slice(0, 200)}` : ""}`);
|
|
331
220
|
}
|
|
332
|
-
const toolCalls = [...tools.entries()].sort(([a], [b]) => a - b).map(([, v]) => ({
|
|
333
|
-
id: v.id ?? "",
|
|
334
|
-
type: "function",
|
|
335
|
-
function: { name: v.name ?? "", arguments: v.arguments }
|
|
336
|
-
}));
|
|
337
|
-
return {
|
|
338
|
-
choices: [{
|
|
339
|
-
finish_reason: finishReason,
|
|
340
|
-
message: {
|
|
341
|
-
content: content || null,
|
|
342
|
-
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
343
|
-
}
|
|
344
|
-
}]
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
const RETRY_TOOL_CALL_ID = "retry_call_0";
|
|
348
|
-
function buildMessages(prompt, system) {
|
|
349
|
-
const messages = [];
|
|
350
|
-
if (system !== void 0) messages.push({ role: "system", content: system });
|
|
351
|
-
messages.push({ role: "user", content: prompt });
|
|
352
|
-
return messages;
|
|
353
|
-
}
|
|
354
|
-
function appendRetry(messages, retry, toolName) {
|
|
355
221
|
messages.push({
|
|
356
222
|
role: "assistant",
|
|
357
|
-
content:
|
|
358
|
-
tool_calls: [{
|
|
359
|
-
id: RETRY_TOOL_CALL_ID,
|
|
360
|
-
type: "function",
|
|
361
|
-
function: { name: toolName, arguments: JSON.stringify(retry.previousOutput) }
|
|
362
|
-
}]
|
|
363
|
-
});
|
|
364
|
-
messages.push({
|
|
365
|
-
role: "tool",
|
|
366
|
-
tool_call_id: RETRY_TOOL_CALL_ID,
|
|
367
|
-
content: retry.feedback
|
|
223
|
+
content: toolUses
|
|
368
224
|
});
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
type: "function",
|
|
393
|
-
function: {
|
|
394
|
-
name: toolName,
|
|
395
|
-
description: "Return the structured output as the function arguments.",
|
|
396
|
-
parameters: structuredParams
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
];
|
|
400
|
-
const toolChoice = helperTools.length > 0 ? "required" : { type: "function", function: { name: toolName } };
|
|
401
|
-
const messages = buildMessages(input.prompt, input.system);
|
|
402
|
-
if (input.retry) appendRetry(messages, input.retry, toolName);
|
|
403
|
-
const opts = {
|
|
404
|
-
tools,
|
|
405
|
-
toolChoice,
|
|
406
|
-
...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {}
|
|
407
|
-
};
|
|
408
|
-
const decodeArgs = (raw) => {
|
|
409
|
-
try {
|
|
410
|
-
return JSON.parse(raw);
|
|
411
|
-
} catch (err) {
|
|
412
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
413
|
-
throw new Error(`\u65E0\u6CD5\u89E3\u6790\u6A21\u578B\u8FD4\u56DE\u7684\u7ED3\u6784\u5316\u6570\u636E: ${message}`);
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
const decode = (raw) => {
|
|
417
|
-
try {
|
|
418
|
-
return Schema.decodeUnknownSync(input.schema)(raw);
|
|
419
|
-
} catch (cause) {
|
|
420
|
-
throw new StructuredOutputDecodeError(raw, cause);
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
for (; ; ) {
|
|
424
|
-
const response = input.onProgress ? await callStream(messages, opts, input.signal, input.onProgress) : await call(messages, opts, input.signal);
|
|
425
|
-
const choice = response.choices[0];
|
|
426
|
-
const structured = choice?.message.tool_calls?.find((c) => c.function.name === toolName);
|
|
427
|
-
if (structured) {
|
|
428
|
-
return decode(decodeArgs(structured.function.arguments));
|
|
429
|
-
}
|
|
430
|
-
const helperCalls = choice?.message.tool_calls ?? [];
|
|
431
|
-
if (helperCalls.length === 0) {
|
|
432
|
-
if (choice?.finish_reason === "length") {
|
|
433
|
-
throw new Error("\u6A21\u578B\u5728\u4EA7\u51FA\u7ED3\u6784\u5316\u7ED3\u679C\u524D\u7528\u5C3D\u4E86 token \u9884\u7B97\uFF08finish_reason=length\uFF09\u3002\u8BF7\u63D0\u9AD8 maxTokens\uFF0C\u6216\u6362\u7528\u975E\u63A8\u7406\u6A21\u578B\u3002");
|
|
434
|
-
}
|
|
435
|
-
const text = choice?.message.content ?? "";
|
|
436
|
-
const reason = choice?.finish_reason ? `\uFF08finish_reason=${choice.finish_reason}\uFF09` : "";
|
|
437
|
-
throw new Error(`\u6A21\u578B\u672A\u8FD4\u56DE\u7ED3\u6784\u5316\u8F93\u51FA${reason}${text ? `: ${text.slice(0, 200)}` : ""}`);
|
|
438
|
-
}
|
|
439
|
-
messages.push({
|
|
440
|
-
role: "assistant",
|
|
441
|
-
content: null,
|
|
442
|
-
tool_calls: helperCalls
|
|
225
|
+
const results = [];
|
|
226
|
+
for (const useBlock of toolUses) {
|
|
227
|
+
const tool = helperByName.get(useBlock.name);
|
|
228
|
+
if (!tool) {
|
|
229
|
+
results.push({
|
|
230
|
+
type: "tool_result",
|
|
231
|
+
tool_use_id: useBlock.id,
|
|
232
|
+
content: `Unknown tool: ${useBlock.name}`
|
|
233
|
+
});
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const result = await tool.execute(useBlock.input ?? {});
|
|
238
|
+
results.push({
|
|
239
|
+
type: "tool_result",
|
|
240
|
+
tool_use_id: useBlock.id,
|
|
241
|
+
content: typeof result === "string" ? result : JSON.stringify(result)
|
|
242
|
+
});
|
|
243
|
+
} catch (err) {
|
|
244
|
+
results.push({
|
|
245
|
+
type: "tool_result",
|
|
246
|
+
tool_use_id: useBlock.id,
|
|
247
|
+
content: err instanceof Error ? err.message : String(err)
|
|
443
248
|
});
|
|
444
|
-
for (const callBlock of helperCalls) {
|
|
445
|
-
const tool = helperByName.get(callBlock.function.name);
|
|
446
|
-
if (!tool) {
|
|
447
|
-
messages.push({
|
|
448
|
-
role: "tool",
|
|
449
|
-
tool_call_id: callBlock.id,
|
|
450
|
-
content: `Unknown tool: ${callBlock.function.name}`
|
|
451
|
-
});
|
|
452
|
-
continue;
|
|
453
|
-
}
|
|
454
|
-
let parsedInput = {};
|
|
455
|
-
try {
|
|
456
|
-
parsedInput = callBlock.function.arguments ? JSON.parse(callBlock.function.arguments) : {};
|
|
457
|
-
} catch {
|
|
458
|
-
}
|
|
459
|
-
try {
|
|
460
|
-
const result = await tool.execute(parsedInput);
|
|
461
|
-
messages.push({
|
|
462
|
-
role: "tool",
|
|
463
|
-
tool_call_id: callBlock.id,
|
|
464
|
-
content: typeof result === "string" ? result : JSON.stringify(result)
|
|
465
|
-
});
|
|
466
|
-
} catch (err) {
|
|
467
|
-
messages.push({
|
|
468
|
-
role: "tool",
|
|
469
|
-
tool_call_id: callBlock.id,
|
|
470
|
-
content: err instanceof Error ? err.message : String(err)
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
249
|
}
|
|
475
250
|
}
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
function buildClient(cfg) {
|
|
479
|
-
switch (cfg.provider) {
|
|
480
|
-
case "anthropic":
|
|
481
|
-
return buildAnthropicClient(cfg);
|
|
482
|
-
case "openai":
|
|
483
|
-
return buildOpenAIClient(cfg);
|
|
484
|
-
default:
|
|
485
|
-
throw new Error(`unsupported AI provider: ${cfg.provider}`);
|
|
251
|
+
messages.push({ role: "user", content: results });
|
|
486
252
|
}
|
|
487
253
|
}
|
|
488
254
|
export default defineNuxtPlugin({
|
|
489
255
|
name: "shwfed:ai",
|
|
490
256
|
setup: () => {
|
|
491
|
-
const config = createConfigRef();
|
|
492
|
-
const allowed = isByokAllowed();
|
|
493
|
-
const available = computed(() => allowed && config.value !== null);
|
|
494
|
-
function setConfig(next) {
|
|
495
|
-
config.value = next;
|
|
496
|
-
}
|
|
497
|
-
function openSettings() {
|
|
498
|
-
settingsOpen.value = true;
|
|
499
|
-
}
|
|
500
|
-
async function generateText(input) {
|
|
501
|
-
const cfg = config.value;
|
|
502
|
-
if (!cfg) throw new Error("AI \u672A\u914D\u7F6E");
|
|
503
|
-
return buildClient(cfg).generateText(input);
|
|
504
|
-
}
|
|
505
|
-
async function generateObject(input) {
|
|
506
|
-
const cfg = config.value;
|
|
507
|
-
if (!cfg) throw new Error("AI \u672A\u914D\u7F6E");
|
|
508
|
-
return buildClient(cfg).generateObject(input);
|
|
509
|
-
}
|
|
510
257
|
const ai = {
|
|
511
|
-
available,
|
|
512
|
-
config,
|
|
513
|
-
setConfig,
|
|
514
|
-
openSettings,
|
|
258
|
+
available: computed(() => true),
|
|
515
259
|
generateText,
|
|
516
260
|
generateObject
|
|
517
261
|
};
|