chatlab-cli 0.24.1 → 0.25.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/dist/{chunk-N5DGZQB4.mjs → chunk-4OMV4VNH.mjs} +567 -97
- package/dist/chunk-4OMV4VNH.mjs.map +1 -0
- package/dist/{chunk-CIIQ3S2X.mjs → chunk-CIBTUWAE.mjs} +7 -7
- package/dist/{chunk-43XWYC3M.mjs → chunk-E65ABM3C.mjs} +168 -72
- package/dist/chunk-E65ABM3C.mjs.map +1 -0
- package/dist/{chunk-ZL322NVL.mjs → chunk-FSHVDWI2.mjs} +109 -44
- package/dist/chunk-FSHVDWI2.mjs.map +1 -0
- package/dist/{chunk-QY6P2YS7.mjs → chunk-GNT5G74Z.mjs} +2 -2
- package/dist/{chunk-QJI6AOAT.mjs → chunk-TCPXAX3F.mjs} +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/{http-TPX74BLK.mjs → http-PMNZ42EN.mjs} +6 -6
- package/dist/{import-B745DRHD.mjs → import-OP7R4CYY.mjs} +4 -4
- package/dist/index.mjs +6 -6
- package/dist/{mcp-YWAVG5XW.mjs → mcp-ABXNFUJO.mjs} +3 -3
- package/dist/{stream-import-OPALPVWF.mjs → stream-import-L6RJHH4L.mjs} +3 -3
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BUwpIerl.js +161 -0
- package/dist-web/assets/{EChartWordcloud-VpNJDurs.js → EChartWordcloud-CzhfrEF_.js} +1 -1
- package/dist-web/assets/{MessageExportModal-CSfaY25B.js → MessageExportModal-BAJKWX4y.js} +1 -1
- package/dist-web/assets/{electron-BUeXfvxT.js → electron-CZt36wW5.js} +1 -1
- package/dist-web/assets/electron-CwERrTWp.js +1 -0
- package/dist-web/assets/{fetch-DzNuFdFM.js → fetch-BxFAkm7O.js} +1 -1
- package/dist-web/assets/{fetch-BohUj3CQ.js → fetch-CgBIWyAo.js} +1 -1
- package/dist-web/assets/{fetch-B2q6973s.js → fetch-D4p9vj1A.js} +1 -1
- package/dist-web/assets/{fetch-Ck3tjoLa.js → fetch-DD1EGRKV.js} +1 -1
- package/dist-web/assets/{fetch-BtHwWs8A.js → fetch-DO8lty7_.js} +1 -1
- package/dist-web/assets/{fetch-BGMRmQx0.js → fetch-DXfZysDf.js} +1 -1
- package/dist-web/assets/{fetch-DypPduyQ.js → fetch-GMkMBzBS.js} +1 -1
- package/dist-web/assets/{fetch-RDFt3hmp.js → fetch-JzVEwamn.js} +1 -1
- package/dist-web/assets/{fetch-CARsBVl0.js → fetch-qoGEVjNg.js} +1 -1
- package/dist-web/assets/{fetch-BneHn5qk.js → fetch-yWwp067l.js} +1 -1
- package/dist-web/assets/{index-Bvlj3dMn.js → index-BrS_VrIY.js} +1 -1
- package/dist-web/assets/index-C1t-kzfo.css +1 -0
- package/dist-web/assets/{index-DCWvD-4L.js → index-Cvlw0RLu.js} +2 -2
- package/dist-web/assets/index-DABpUm3J.js +9 -0
- package/dist-web/assets/{index-C5LrQG3N.js → index-DvWI6Yqa.js} +4 -4
- package/dist-web/assets/{index-BvaWRM6_.js → index-O0PG26_v.js} +1 -1
- package/dist-web/assets/index-OsjX5hXw.js +173 -0
- package/dist-web/assets/vendor-echarts-CITQeskI.js +11 -0
- package/dist-web/assets/{vendor-echarts-wordcloud-CZ9gsX8l.js → vendor-echarts-wordcloud-B1kQMklB.js} +1 -1
- package/dist-web/assets/{vendor-nuxt-ui-BYU7dz8t.js → vendor-nuxt-ui-C_8CsH6e.js} +1 -1
- package/dist-web/assets/{vendor-reka-ui-CnB0mMNX.js → vendor-reka-ui-CIMXwvEp.js} +1 -1
- package/dist-web/assets/{web-CXPkmhis.js → web-4rtrAcLu.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chunk-43XWYC3M.mjs.map +0 -1
- package/dist/chunk-N5DGZQB4.mjs.map +0 -1
- package/dist/chunk-ZL322NVL.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BBDrsJfe.js +0 -161
- package/dist-web/assets/electron-BynNUuEA.js +0 -1
- package/dist-web/assets/index-BRwEubUe.js +0 -173
- package/dist-web/assets/index-DB-iqXzV.css +0 -1
- package/dist-web/assets/index-DS1rzk1I.js +0 -8
- package/dist-web/assets/vendor-echarts-C5u62NnM.js +0 -11
- /package/dist/{chunk-CIIQ3S2X.mjs.map → chunk-CIBTUWAE.mjs.map} +0 -0
- /package/dist/{chunk-QY6P2YS7.mjs.map → chunk-GNT5G74Z.mjs.map} +0 -0
- /package/dist/{chunk-QJI6AOAT.mjs.map → chunk-TCPXAX3F.mjs.map} +0 -0
- /package/dist/{http-TPX74BLK.mjs.map → http-PMNZ42EN.mjs.map} +0 -0
- /package/dist/{import-B745DRHD.mjs.map → import-OP7R4CYY.mjs.map} +0 -0
- /package/dist/{mcp-YWAVG5XW.mjs.map → mcp-ABXNFUJO.mjs.map} +0 -0
- /package/dist/{stream-import-OPALPVWF.mjs.map → stream-import-L6RJHH4L.mjs.map} +0 -0
|
@@ -4410,6 +4410,218 @@ function isNewerStableVersion(latest, current) {
|
|
|
4410
4410
|
return currentVersion.prerelease;
|
|
4411
4411
|
}
|
|
4412
4412
|
|
|
4413
|
+
// ../../packages/core/src/chart/index.ts
|
|
4414
|
+
var ChartValidationError = class extends Error {
|
|
4415
|
+
constructor(message) {
|
|
4416
|
+
super(message);
|
|
4417
|
+
this.name = "ChartValidationError";
|
|
4418
|
+
}
|
|
4419
|
+
};
|
|
4420
|
+
var CHART_TYPES = /* @__PURE__ */ new Set(["bar", "line", "pie", "heatmap"]);
|
|
4421
|
+
function isRecord(value) {
|
|
4422
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4423
|
+
}
|
|
4424
|
+
function asFieldName(value, label) {
|
|
4425
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
4426
|
+
throw new ChartValidationError(`${label} must be a non-empty field name`);
|
|
4427
|
+
}
|
|
4428
|
+
return value;
|
|
4429
|
+
}
|
|
4430
|
+
function assertFieldExists(rows, field) {
|
|
4431
|
+
if (rows.length === 0) return;
|
|
4432
|
+
if (!Object.prototype.hasOwnProperty.call(rows[0], field)) {
|
|
4433
|
+
throw new ChartValidationError(`Field "${field}" does not exist in SQL result`);
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4436
|
+
function toLabel(value) {
|
|
4437
|
+
if (value === null || value === void 0 || value === "") return "(empty)";
|
|
4438
|
+
return String(value);
|
|
4439
|
+
}
|
|
4440
|
+
function toNumber(value, field) {
|
|
4441
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
4442
|
+
if (!Number.isFinite(num)) {
|
|
4443
|
+
throw new ChartValidationError(`Field "${field}" contains non-numeric value "${String(value)}"`);
|
|
4444
|
+
}
|
|
4445
|
+
return num;
|
|
4446
|
+
}
|
|
4447
|
+
function inferFieldType(values) {
|
|
4448
|
+
const present = values.filter((v) => v !== null && v !== void 0);
|
|
4449
|
+
if (present.length === 0) return "string";
|
|
4450
|
+
if (present.every((v) => typeof v === "number" && Number.isInteger(v))) return "integer";
|
|
4451
|
+
if (present.every(
|
|
4452
|
+
(v) => typeof v === "number" || typeof v === "string" && v.trim() !== "" && !Number.isNaN(Number(v))
|
|
4453
|
+
)) {
|
|
4454
|
+
return "number";
|
|
4455
|
+
}
|
|
4456
|
+
if (present.every((v) => typeof v === "boolean")) return "boolean";
|
|
4457
|
+
return "category";
|
|
4458
|
+
}
|
|
4459
|
+
function normalizeChartSpec(raw) {
|
|
4460
|
+
if (!isRecord(raw)) throw new ChartValidationError("chartSpec must be an object");
|
|
4461
|
+
if (raw.version !== 1) throw new ChartValidationError("chartSpec.version must be 1");
|
|
4462
|
+
if (typeof raw.type !== "string" || !CHART_TYPES.has(raw.type)) {
|
|
4463
|
+
throw new ChartValidationError("chartSpec.type must be one of: bar, line, pie, heatmap");
|
|
4464
|
+
}
|
|
4465
|
+
if (typeof raw.title !== "string" || raw.title.trim().length === 0) {
|
|
4466
|
+
throw new ChartValidationError("chartSpec.title must be a non-empty string");
|
|
4467
|
+
}
|
|
4468
|
+
if (!isRecord(raw.encoding)) throw new ChartValidationError("chartSpec.encoding must be an object");
|
|
4469
|
+
const spec = raw;
|
|
4470
|
+
switch (spec.type) {
|
|
4471
|
+
case "bar":
|
|
4472
|
+
case "line":
|
|
4473
|
+
asFieldName(spec.encoding.x, "encoding.x");
|
|
4474
|
+
asFieldName(spec.encoding.y, "encoding.y");
|
|
4475
|
+
break;
|
|
4476
|
+
case "pie":
|
|
4477
|
+
asFieldName(spec.encoding.label, "encoding.label");
|
|
4478
|
+
asFieldName(spec.encoding.value, "encoding.value");
|
|
4479
|
+
break;
|
|
4480
|
+
case "heatmap":
|
|
4481
|
+
asFieldName(spec.encoding.x, "encoding.x");
|
|
4482
|
+
asFieldName(spec.encoding.y, "encoding.y");
|
|
4483
|
+
asFieldName(spec.encoding.value, "encoding.value");
|
|
4484
|
+
break;
|
|
4485
|
+
}
|
|
4486
|
+
return {
|
|
4487
|
+
...spec,
|
|
4488
|
+
title: spec.title.trim()
|
|
4489
|
+
};
|
|
4490
|
+
}
|
|
4491
|
+
function inferChartDataset(rows, declaredFields) {
|
|
4492
|
+
const declared = new Map((declaredFields ?? []).map((field) => [field.name, field]));
|
|
4493
|
+
const columnNames = rows.length > 0 ? Object.keys(rows[0]) : [...declared.keys()];
|
|
4494
|
+
const columns = columnNames.map((name) => {
|
|
4495
|
+
const declaredField = declared.get(name);
|
|
4496
|
+
if (declaredField) return declaredField;
|
|
4497
|
+
return {
|
|
4498
|
+
name,
|
|
4499
|
+
type: inferFieldType(rows.map((row) => row[name]))
|
|
4500
|
+
};
|
|
4501
|
+
});
|
|
4502
|
+
return { columns, rows };
|
|
4503
|
+
}
|
|
4504
|
+
function aggregateByLabel(rows, labelField, valueField) {
|
|
4505
|
+
const labels = [];
|
|
4506
|
+
const indexByLabel = /* @__PURE__ */ new Map();
|
|
4507
|
+
const values = [];
|
|
4508
|
+
for (const row of rows) {
|
|
4509
|
+
const label = toLabel(row[labelField]);
|
|
4510
|
+
let index = indexByLabel.get(label);
|
|
4511
|
+
if (index === void 0) {
|
|
4512
|
+
index = labels.length;
|
|
4513
|
+
indexByLabel.set(label, index);
|
|
4514
|
+
labels.push(label);
|
|
4515
|
+
values.push(0);
|
|
4516
|
+
}
|
|
4517
|
+
values[index] += toNumber(row[valueField], valueField);
|
|
4518
|
+
}
|
|
4519
|
+
return { labels, values };
|
|
4520
|
+
}
|
|
4521
|
+
function buildLineData(rows, spec) {
|
|
4522
|
+
const xField = spec.encoding.x;
|
|
4523
|
+
const yField = spec.encoding.y;
|
|
4524
|
+
const seriesField = spec.encoding.series;
|
|
4525
|
+
if (!seriesField) return aggregateByLabel(rows, xField, yField);
|
|
4526
|
+
assertFieldExists(rows, seriesField);
|
|
4527
|
+
const labels = [];
|
|
4528
|
+
const labelIndex = /* @__PURE__ */ new Map();
|
|
4529
|
+
const seriesNames = [];
|
|
4530
|
+
const seriesIndex = /* @__PURE__ */ new Map();
|
|
4531
|
+
const matrix = [];
|
|
4532
|
+
for (const row of rows) {
|
|
4533
|
+
const label = toLabel(row[xField]);
|
|
4534
|
+
const seriesName = toLabel(row[seriesField]);
|
|
4535
|
+
let xIndex = labelIndex.get(label);
|
|
4536
|
+
if (xIndex === void 0) {
|
|
4537
|
+
xIndex = labels.length;
|
|
4538
|
+
labelIndex.set(label, xIndex);
|
|
4539
|
+
labels.push(label);
|
|
4540
|
+
for (const values of matrix) values.push(0);
|
|
4541
|
+
}
|
|
4542
|
+
let sIndex = seriesIndex.get(seriesName);
|
|
4543
|
+
if (sIndex === void 0) {
|
|
4544
|
+
sIndex = seriesNames.length;
|
|
4545
|
+
seriesIndex.set(seriesName, sIndex);
|
|
4546
|
+
seriesNames.push(seriesName);
|
|
4547
|
+
matrix.push(Array(labels.length).fill(0));
|
|
4548
|
+
}
|
|
4549
|
+
matrix[sIndex][xIndex] += toNumber(row[yField], yField);
|
|
4550
|
+
}
|
|
4551
|
+
const series = seriesNames.map((name, index) => ({ name, values: matrix[index] }));
|
|
4552
|
+
return {
|
|
4553
|
+
labels,
|
|
4554
|
+
values: series[0]?.values ?? [],
|
|
4555
|
+
series
|
|
4556
|
+
};
|
|
4557
|
+
}
|
|
4558
|
+
function buildHeatmapData(rows, spec) {
|
|
4559
|
+
const xField = spec.encoding.x;
|
|
4560
|
+
const yField = spec.encoding.y;
|
|
4561
|
+
const valueField = spec.encoding.value;
|
|
4562
|
+
const xLabels = [];
|
|
4563
|
+
const yLabels = [];
|
|
4564
|
+
const xIndex = /* @__PURE__ */ new Map();
|
|
4565
|
+
const yIndex = /* @__PURE__ */ new Map();
|
|
4566
|
+
const values = /* @__PURE__ */ new Map();
|
|
4567
|
+
for (const row of rows) {
|
|
4568
|
+
const xLabel = toLabel(row[xField]);
|
|
4569
|
+
const yLabel = toLabel(row[yField]);
|
|
4570
|
+
let xi = xIndex.get(xLabel);
|
|
4571
|
+
if (xi === void 0) {
|
|
4572
|
+
xi = xLabels.length;
|
|
4573
|
+
xIndex.set(xLabel, xi);
|
|
4574
|
+
xLabels.push(xLabel);
|
|
4575
|
+
}
|
|
4576
|
+
let yi = yIndex.get(yLabel);
|
|
4577
|
+
if (yi === void 0) {
|
|
4578
|
+
yi = yLabels.length;
|
|
4579
|
+
yIndex.set(yLabel, yi);
|
|
4580
|
+
yLabels.push(yLabel);
|
|
4581
|
+
}
|
|
4582
|
+
const key = `${xi}:${yi}`;
|
|
4583
|
+
values.set(key, (values.get(key) ?? 0) + toNumber(row[valueField], valueField));
|
|
4584
|
+
}
|
|
4585
|
+
const data = [];
|
|
4586
|
+
for (const [key, value] of values.entries()) {
|
|
4587
|
+
const [x, y] = key.split(":").map(Number);
|
|
4588
|
+
data.push([x, y, value]);
|
|
4589
|
+
}
|
|
4590
|
+
return { xLabels, yLabels, data };
|
|
4591
|
+
}
|
|
4592
|
+
function buildChartPayload(rows, rawSpec, options) {
|
|
4593
|
+
const spec = normalizeChartSpec(rawSpec);
|
|
4594
|
+
const dataset = inferChartDataset(rows, spec.fields);
|
|
4595
|
+
const requiredFields = /* @__PURE__ */ new Set();
|
|
4596
|
+
for (const field of Object.values(spec.encoding)) {
|
|
4597
|
+
if (typeof field === "string" && field) requiredFields.add(field);
|
|
4598
|
+
}
|
|
4599
|
+
for (const field of requiredFields) assertFieldExists(rows, field);
|
|
4600
|
+
let data;
|
|
4601
|
+
switch (spec.type) {
|
|
4602
|
+
case "bar":
|
|
4603
|
+
data = aggregateByLabel(rows, spec.encoding.x, spec.encoding.y);
|
|
4604
|
+
break;
|
|
4605
|
+
case "line":
|
|
4606
|
+
data = buildLineData(rows, spec);
|
|
4607
|
+
break;
|
|
4608
|
+
case "pie":
|
|
4609
|
+
data = aggregateByLabel(rows, spec.encoding.label, spec.encoding.value);
|
|
4610
|
+
break;
|
|
4611
|
+
case "heatmap":
|
|
4612
|
+
data = buildHeatmapData(rows, spec);
|
|
4613
|
+
break;
|
|
4614
|
+
}
|
|
4615
|
+
return {
|
|
4616
|
+
version: 1,
|
|
4617
|
+
spec,
|
|
4618
|
+
dataset,
|
|
4619
|
+
data,
|
|
4620
|
+
rowCount: rows.length,
|
|
4621
|
+
truncated: options?.truncated
|
|
4622
|
+
};
|
|
4623
|
+
}
|
|
4624
|
+
|
|
4413
4625
|
// ../../packages/core/src/nlp/pos-tags.ts
|
|
4414
4626
|
var POS_TAG_DEFINITIONS = [
|
|
4415
4627
|
{ tag: "n", name: "\u540D\u8BCD", description: "\u666E\u901A\u540D\u8BCD", meaningful: true },
|
|
@@ -5248,6 +5460,7 @@ var BUILTIN_TOOL_CATALOG = [
|
|
|
5248
5460
|
{ name: "search_sessions", category: "core" },
|
|
5249
5461
|
{ name: "get_session_messages", category: "core" },
|
|
5250
5462
|
{ name: "get_members", category: "core" },
|
|
5463
|
+
{ name: "get_schema", category: "core" },
|
|
5251
5464
|
// Analysis 工具
|
|
5252
5465
|
{ name: "get_member_stats", category: "analysis" },
|
|
5253
5466
|
{ name: "get_time_stats", category: "analysis" },
|
|
@@ -5256,6 +5469,8 @@ var BUILTIN_TOOL_CATALOG = [
|
|
|
5256
5469
|
{ name: "get_session_summaries", category: "analysis" },
|
|
5257
5470
|
{ name: "response_time_analysis", category: "analysis" },
|
|
5258
5471
|
{ name: "keyword_frequency", category: "analysis" },
|
|
5472
|
+
{ name: "render_chart", category: "analysis" },
|
|
5473
|
+
{ name: "execute_sql", category: "analysis" },
|
|
5259
5474
|
// SQL Analysis 工具
|
|
5260
5475
|
{ name: "message_type_breakdown", category: "analysis" },
|
|
5261
5476
|
{ name: "peak_chat_hours_by_member", category: "analysis" },
|
|
@@ -5270,6 +5485,9 @@ var BUILTIN_TOOL_CATALOG = [
|
|
|
5270
5485
|
{ name: "unanswered_messages", category: "analysis" }
|
|
5271
5486
|
];
|
|
5272
5487
|
|
|
5488
|
+
// ../../packages/core/src/ai/chart-capability.ts
|
|
5489
|
+
var CHART_CAPABILITY_SKILL_ID = "chart_runtime";
|
|
5490
|
+
|
|
5273
5491
|
// ../../packages/core/src/ai/provider-registry.ts
|
|
5274
5492
|
var OPENAI = {
|
|
5275
5493
|
id: "openai",
|
|
@@ -13394,93 +13612,43 @@ function countMessagesTokens(messages, systemPrompt) {
|
|
|
13394
13612
|
// ../../packages/node-runtime/src/ai/skill-manager.ts
|
|
13395
13613
|
import * as fs30 from "fs";
|
|
13396
13614
|
import * as path27 from "path";
|
|
13397
|
-
|
|
13615
|
+
|
|
13616
|
+
// ../../packages/node-runtime/src/ai/skill-menu.ts
|
|
13398
13617
|
var MAX_SKILL_MENU_ITEMS = 15;
|
|
13399
|
-
var
|
|
13400
|
-
info: () => {
|
|
13401
|
-
},
|
|
13402
|
-
warn: () => {
|
|
13403
|
-
}
|
|
13404
|
-
};
|
|
13405
|
-
var SkillManager = class {
|
|
13406
|
-
skills = /* @__PURE__ */ new Map();
|
|
13407
|
-
initialized = false;
|
|
13408
|
-
skillsDir;
|
|
13409
|
-
logger;
|
|
13410
|
-
constructor(aiDataDir, logger) {
|
|
13411
|
-
this.skillsDir = path27.join(aiDataDir, SKILLS_DIR_NAME);
|
|
13412
|
-
this.logger = logger ?? defaultLogger2;
|
|
13413
|
-
}
|
|
13414
|
-
init() {
|
|
13415
|
-
this.loadAll();
|
|
13416
|
-
this.initialized = true;
|
|
13417
|
-
this.logger.info(`SkillManager initialized: ${this.skills.size} skills`);
|
|
13418
|
-
return { total: this.skills.size };
|
|
13419
|
-
}
|
|
13420
|
-
getSkillConfig(id) {
|
|
13421
|
-
this.ensureInitialized();
|
|
13422
|
-
return this.skills.get(id) ?? null;
|
|
13423
|
-
}
|
|
13424
|
-
getAllSkills() {
|
|
13425
|
-
this.ensureInitialized();
|
|
13426
|
-
return Array.from(this.skills.values()).map((def) => ({
|
|
13427
|
-
id: def.id,
|
|
13428
|
-
name: def.name,
|
|
13429
|
-
description: def.description,
|
|
13430
|
-
tags: def.tags,
|
|
13431
|
-
chatScope: def.chatScope,
|
|
13432
|
-
tools: def.tools,
|
|
13433
|
-
builtinId: def.builtinId
|
|
13434
|
-
}));
|
|
13435
|
-
}
|
|
13436
|
-
/**
|
|
13437
|
-
* 构建 AI 自选技能菜单文本
|
|
13438
|
-
* 只包含与当前 chatType + 助手工具权限兼容的技能
|
|
13439
|
-
*/
|
|
13440
|
-
getSkillMenu(chatType, allowedTools) {
|
|
13441
|
-
this.ensureInitialized();
|
|
13442
|
-
const compatible = Array.from(this.skills.values()).filter((skill) => {
|
|
13443
|
-
if (skill.chatScope !== "all" && skill.chatScope !== chatType) return false;
|
|
13444
|
-
if (skill.tools.length > 0 && allowedTools && allowedTools.length > 0) {
|
|
13445
|
-
const allCovered = skill.tools.every((t2) => allowedTools.includes(t2));
|
|
13446
|
-
if (!allCovered) return false;
|
|
13447
|
-
}
|
|
13448
|
-
return true;
|
|
13449
|
-
});
|
|
13450
|
-
if (compatible.length === 0) return null;
|
|
13451
|
-
const items = compatible.slice(0, MAX_SKILL_MENU_ITEMS);
|
|
13452
|
-
const lines = items.map((s) => `- ${s.id}: ${s.name} \u2014 ${s.description}`);
|
|
13453
|
-
return `## \u53EF\u7528\u6280\u80FD
|
|
13618
|
+
var SKILL_MENU_HEADER = `## \u53EF\u7528\u6280\u80FD
|
|
13454
13619
|
\u4EE5\u4E0B\u662F\u4F60\u53EF\u4EE5\u4F7F\u7528\u7684\u5206\u6790\u6280\u80FD\u3002\u5F53\u4F60\u5224\u65AD\u7528\u6237\u7684\u95EE\u9898\u9002\u5408\u4F7F\u7528\u67D0\u4E2A\u6280\u80FD\u65F6\uFF0C
|
|
13455
|
-
\u8BF7\u8C03\u7528 activate_skill \u5DE5\u5177\u6FC0\u6D3B\u5B83\uFF0C\u7136\u540E\u6309\u7167\u8FD4\u56DE\u7684\u6307\u5BFC\u5B8C\u6210\u4EFB\u52A1\u3002
|
|
13620
|
+
\u8BF7\u8C03\u7528 activate_skill \u5DE5\u5177\u6FC0\u6D3B\u5B83\uFF0C\u7136\u540E\u6309\u7167\u8FD4\u56DE\u7684\u6307\u5BFC\u5B8C\u6210\u4EFB\u52A1\u3002`;
|
|
13621
|
+
var SKILL_MENU_CLOSING = "\u5982\u679C\u7528\u6237\u7684\u95EE\u9898\u4E0D\u9700\u8981\u4F7F\u7528\u6280\u80FD\uFF0C\u76F4\u63A5\u56DE\u7B54\u5373\u53EF\u3002";
|
|
13622
|
+
var SKILL_MENU_CLOSING_BLOCK = `
|
|
13456
13623
|
|
|
13457
|
-
${
|
|
13624
|
+
${SKILL_MENU_CLOSING}`;
|
|
13625
|
+
function formatSkillMenuLine(item) {
|
|
13626
|
+
const guidanceSuffix = item.guidance ? `. ${item.guidance}` : "";
|
|
13627
|
+
return `- ${item.id}: ${item.name} \u2014 ${item.description}${guidanceSuffix}`;
|
|
13628
|
+
}
|
|
13629
|
+
function buildSkillMenuText(lines) {
|
|
13630
|
+
const visibleLines = normalizeSkillMenuLines(lines);
|
|
13631
|
+
if (visibleLines.length === 0) return null;
|
|
13632
|
+
return `${SKILL_MENU_HEADER}
|
|
13458
13633
|
|
|
13459
|
-
\
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
try {
|
|
13472
|
-
const filePath = path27.join(this.skillsDir, file);
|
|
13473
|
-
const content = fs30.readFileSync(filePath, "utf-8");
|
|
13474
|
-
const def = parseSkillFile(content, filePath);
|
|
13475
|
-
if (def) {
|
|
13476
|
-
this.skills.set(def.id, def);
|
|
13477
|
-
}
|
|
13478
|
-
} catch (error) {
|
|
13479
|
-
this.logger.warn(`Failed to load skill: ${file}`, { error: String(error) });
|
|
13480
|
-
}
|
|
13481
|
-
}
|
|
13634
|
+
${visibleLines.join("\n")}
|
|
13635
|
+
|
|
13636
|
+
${SKILL_MENU_CLOSING}`;
|
|
13637
|
+
}
|
|
13638
|
+
function appendSkillMenuLines(baseMenu, lines) {
|
|
13639
|
+
const visibleLines = normalizeSkillMenuLines(lines);
|
|
13640
|
+
if (visibleLines.length === 0) return baseMenu ?? null;
|
|
13641
|
+
if (!baseMenu) return buildSkillMenuText(visibleLines);
|
|
13642
|
+
const insertion = `
|
|
13643
|
+
${visibleLines.join("\n")}`;
|
|
13644
|
+
if (!baseMenu.includes(SKILL_MENU_CLOSING_BLOCK)) {
|
|
13645
|
+
return `${baseMenu}${insertion}`;
|
|
13482
13646
|
}
|
|
13483
|
-
};
|
|
13647
|
+
return baseMenu.replace(SKILL_MENU_CLOSING_BLOCK, `${insertion}${SKILL_MENU_CLOSING_BLOCK}`);
|
|
13648
|
+
}
|
|
13649
|
+
function normalizeSkillMenuLines(lines) {
|
|
13650
|
+
return lines.map((line) => line.trim()).filter(Boolean);
|
|
13651
|
+
}
|
|
13484
13652
|
|
|
13485
13653
|
// ../../packages/node-runtime/src/ai/skill-manager-core.ts
|
|
13486
13654
|
function toSummary2(def) {
|
|
@@ -13511,7 +13679,6 @@ function simpleHash(content) {
|
|
|
13511
13679
|
}
|
|
13512
13680
|
return hash.toString(36);
|
|
13513
13681
|
}
|
|
13514
|
-
var MAX_SKILL_MENU_ITEMS2 = 15;
|
|
13515
13682
|
var SkillManagerCore = class {
|
|
13516
13683
|
deps;
|
|
13517
13684
|
builtinDefs = /* @__PURE__ */ new Map();
|
|
@@ -13665,21 +13832,14 @@ var SkillManagerCore = class {
|
|
|
13665
13832
|
this.ensureInitialized();
|
|
13666
13833
|
const compatible = Array.from(this.cache.values()).filter((skill) => {
|
|
13667
13834
|
if (skill.chatScope !== "all" && skill.chatScope !== chatType) return false;
|
|
13668
|
-
if (skill.tools.length > 0 && allowedTools
|
|
13835
|
+
if (skill.tools.length > 0 && allowedTools !== void 0) {
|
|
13669
13836
|
if (!skill.tools.every((t2) => allowedTools.includes(t2))) return false;
|
|
13670
13837
|
}
|
|
13671
13838
|
return true;
|
|
13672
13839
|
});
|
|
13673
13840
|
if (compatible.length === 0) return null;
|
|
13674
|
-
const items = compatible.slice(0,
|
|
13675
|
-
|
|
13676
|
-
return `## \u53EF\u7528\u6280\u80FD
|
|
13677
|
-
\u4EE5\u4E0B\u662F\u4F60\u53EF\u4EE5\u4F7F\u7528\u7684\u5206\u6790\u6280\u80FD\u3002\u5F53\u4F60\u5224\u65AD\u7528\u6237\u7684\u95EE\u9898\u9002\u5408\u4F7F\u7528\u67D0\u4E2A\u6280\u80FD\u65F6\uFF0C
|
|
13678
|
-
\u8BF7\u8C03\u7528 activate_skill \u5DE5\u5177\u6FC0\u6D3B\u5B83\uFF0C\u7136\u540E\u6309\u7167\u8FD4\u56DE\u7684\u6307\u5BFC\u5B8C\u6210\u4EFB\u52A1\u3002
|
|
13679
|
-
|
|
13680
|
-
${lines.join("\n")}
|
|
13681
|
-
|
|
13682
|
-
\u5982\u679C\u7528\u6237\u7684\u95EE\u9898\u4E0D\u9700\u8981\u4F7F\u7528\u6280\u80FD\uFF0C\u76F4\u63A5\u56DE\u7B54\u5373\u53EF\u3002`;
|
|
13841
|
+
const items = compatible.slice(0, MAX_SKILL_MENU_ITEMS);
|
|
13842
|
+
return buildSkillMenuText(items.map(formatSkillMenuLine));
|
|
13683
13843
|
}
|
|
13684
13844
|
// ==================== Internal ====================
|
|
13685
13845
|
findByBuiltinId(builtinId) {
|
|
@@ -13709,6 +13869,80 @@ ${lines.join("\n")}
|
|
|
13709
13869
|
}
|
|
13710
13870
|
};
|
|
13711
13871
|
|
|
13872
|
+
// ../../packages/node-runtime/src/ai/skill-manager.ts
|
|
13873
|
+
var SKILLS_DIR_NAME = "skills";
|
|
13874
|
+
var defaultLogger2 = {
|
|
13875
|
+
info: () => {
|
|
13876
|
+
},
|
|
13877
|
+
warn: () => {
|
|
13878
|
+
}
|
|
13879
|
+
};
|
|
13880
|
+
var nodeFs = {
|
|
13881
|
+
ensureDir(dir) {
|
|
13882
|
+
fs30.mkdirSync(dir, { recursive: true });
|
|
13883
|
+
},
|
|
13884
|
+
listFiles(dir, ext) {
|
|
13885
|
+
if (!fs30.existsSync(dir)) return [];
|
|
13886
|
+
return fs30.readdirSync(dir).filter((file) => file.endsWith(ext));
|
|
13887
|
+
},
|
|
13888
|
+
readFile(filePath) {
|
|
13889
|
+
return fs30.readFileSync(filePath, "utf-8");
|
|
13890
|
+
},
|
|
13891
|
+
writeFile(filePath, content) {
|
|
13892
|
+
fs30.writeFileSync(filePath, content, "utf-8");
|
|
13893
|
+
},
|
|
13894
|
+
deleteFile(filePath) {
|
|
13895
|
+
fs30.unlinkSync(filePath);
|
|
13896
|
+
},
|
|
13897
|
+
fileExists(filePath) {
|
|
13898
|
+
return fs30.existsSync(filePath);
|
|
13899
|
+
},
|
|
13900
|
+
joinPath(...parts) {
|
|
13901
|
+
return path27.join(...parts);
|
|
13902
|
+
}
|
|
13903
|
+
};
|
|
13904
|
+
var SkillManager = class {
|
|
13905
|
+
core;
|
|
13906
|
+
logger;
|
|
13907
|
+
constructor(aiDataDir, logger) {
|
|
13908
|
+
this.logger = logger ?? defaultLogger2;
|
|
13909
|
+
this.core = new SkillManagerCore({
|
|
13910
|
+
fs: nodeFs,
|
|
13911
|
+
skillsDir: path27.join(aiDataDir, SKILLS_DIR_NAME),
|
|
13912
|
+
builtinRawSkills: [],
|
|
13913
|
+
logger: {
|
|
13914
|
+
info: () => {
|
|
13915
|
+
},
|
|
13916
|
+
warn: (_category, message, data) => this.logger.warn(message, toLoggerExtra(data)),
|
|
13917
|
+
error: (_category, message, data) => this.logger.warn(message, toLoggerExtra(data))
|
|
13918
|
+
}
|
|
13919
|
+
});
|
|
13920
|
+
}
|
|
13921
|
+
init() {
|
|
13922
|
+
const result = this.core.init();
|
|
13923
|
+
this.logger.info(`SkillManager initialized: ${result.total} skills`);
|
|
13924
|
+
return result;
|
|
13925
|
+
}
|
|
13926
|
+
getSkillConfig(id) {
|
|
13927
|
+
return this.core.getSkillConfig(id);
|
|
13928
|
+
}
|
|
13929
|
+
getAllSkills() {
|
|
13930
|
+
return this.core.getAllSkills();
|
|
13931
|
+
}
|
|
13932
|
+
/**
|
|
13933
|
+
* 构建 AI 自选技能菜单文本
|
|
13934
|
+
* 只包含与当前 chatType + 助手工具权限兼容的技能
|
|
13935
|
+
*/
|
|
13936
|
+
getSkillMenu(chatType, allowedTools) {
|
|
13937
|
+
return this.core.getSkillMenu(chatType, allowedTools);
|
|
13938
|
+
}
|
|
13939
|
+
};
|
|
13940
|
+
function toLoggerExtra(data) {
|
|
13941
|
+
if (data === void 0) return void 0;
|
|
13942
|
+
if (data && typeof data === "object" && !Array.isArray(data)) return data;
|
|
13943
|
+
return { data };
|
|
13944
|
+
}
|
|
13945
|
+
|
|
13712
13946
|
// ../../packages/node-runtime/src/ai/activate-skill-tool.ts
|
|
13713
13947
|
function createActivateSkillTool(options) {
|
|
13714
13948
|
const { chatType, allowedTools, coreToolNames, getSkillConfig, locale = "zh-CN" } = options;
|
|
@@ -13744,7 +13978,7 @@ function createActivateSkillTool(options) {
|
|
|
13744
13978
|
details: { skillId, found: true, applicable: false }
|
|
13745
13979
|
};
|
|
13746
13980
|
}
|
|
13747
|
-
if (skill.tools.length > 0 && allowedTools
|
|
13981
|
+
if (skill.tools.length > 0 && allowedTools !== void 0) {
|
|
13748
13982
|
const missing = skill.tools.filter((t2) => !(coreToolNames?.has(t2) ?? false) && !allowedTools.includes(t2));
|
|
13749
13983
|
if (missing.length > 0) {
|
|
13750
13984
|
const msg = isZh ? `\u5F53\u524D\u52A9\u624B\u7F3A\u5C11\u8BE5\u6280\u80FD\u6240\u9700\u7684\u5DE5\u5177\uFF1A${missing.join(", ")}` : `Current assistant lacks tools required by this skill: ${missing.join(", ")}`;
|
|
@@ -13763,6 +13997,175 @@ function createActivateSkillTool(options) {
|
|
|
13763
13997
|
};
|
|
13764
13998
|
}
|
|
13765
13999
|
|
|
14000
|
+
// ../../packages/node-runtime/src/ai/chart-runtime.ts
|
|
14001
|
+
var CHART_CAPABILITY_CORE_TOOLS = ["get_schema"];
|
|
14002
|
+
var CHART_CAPABILITY_ANALYSIS_TOOLS = ["render_chart"];
|
|
14003
|
+
var RAW_SQL_TOOL_NAMES = /* @__PURE__ */ new Set(["execute_sql"]);
|
|
14004
|
+
function getChartCapabilityAllowedBuiltinTools(allowedTools) {
|
|
14005
|
+
const baseTools = (allowedTools ?? []).filter((toolName) => !RAW_SQL_TOOL_NAMES.has(toolName));
|
|
14006
|
+
return Array.from(/* @__PURE__ */ new Set([...baseTools, ...CHART_CAPABILITY_ANALYSIS_TOOLS]));
|
|
14007
|
+
}
|
|
14008
|
+
function getAllowedBuiltinToolsForChartAutoSkill(allowedTools) {
|
|
14009
|
+
if (!allowedTools) return void 0;
|
|
14010
|
+
if (allowedTools.length === 0) return [];
|
|
14011
|
+
return Array.from(/* @__PURE__ */ new Set([...allowedTools, ...CHART_CAPABILITY_ANALYSIS_TOOLS]));
|
|
14012
|
+
}
|
|
14013
|
+
function shouldUseChartCapabilityForMessage(message) {
|
|
14014
|
+
const normalized = message.trim().toLowerCase();
|
|
14015
|
+
if (!normalized) return false;
|
|
14016
|
+
return /(?:画|绘制|生成|做|出|展示).{0,8}(?:图|图表)|(?:图表|可视化|饼图|柱状图|条形图|折线图|热力图|趋势图|占比图|分布图|chart|charts|plot|visuali[sz]e|visuali[sz]ation|pie chart|bar chart|line chart|heatmap)/i.test(
|
|
14017
|
+
normalized
|
|
14018
|
+
);
|
|
14019
|
+
}
|
|
14020
|
+
function resolveChartRuntimeForRequest(options) {
|
|
14021
|
+
const locale = options.locale ?? "zh-CN";
|
|
14022
|
+
const isExplicitChartSkill = options.skillId === CHART_CAPABILITY_SKILL_ID;
|
|
14023
|
+
const isAutoChartSkill = options.enableAutoDetection === true && !options.skillId && shouldUseChartCapabilityForMessage(options.userMessage ?? "");
|
|
14024
|
+
if (!isExplicitChartSkill && !isAutoChartSkill) {
|
|
14025
|
+
return { isChartCapability: false };
|
|
14026
|
+
}
|
|
14027
|
+
return {
|
|
14028
|
+
isChartCapability: true,
|
|
14029
|
+
skillDef: { ...getChartCapabilitySkill(locale), chatScope: "all" },
|
|
14030
|
+
allowedBuiltinTools: getChartCapabilityAllowedBuiltinTools(options.assistantAllowedTools)
|
|
14031
|
+
};
|
|
14032
|
+
}
|
|
14033
|
+
function getChartCapabilitySkill(locale = "zh-CN") {
|
|
14034
|
+
const isZh = locale.startsWith("zh");
|
|
14035
|
+
return {
|
|
14036
|
+
id: CHART_CAPABILITY_SKILL_ID,
|
|
14037
|
+
name: isZh ? "\u7ED8\u56FE\u52A9\u624B" : "Chart Assistant",
|
|
14038
|
+
description: isZh ? "\u6309\u672C\u8F6E\u95EE\u9898\u751F\u6210\u7075\u6D3B\u7684\u804A\u5929\u6570\u636E\u56FE\u8868" : "Generate flexible charts for this chat question",
|
|
14039
|
+
tags: [isZh ? "\u56FE\u8868" : "chart"],
|
|
14040
|
+
chatScope: "all",
|
|
14041
|
+
tools: ["render_chart", "get_schema"],
|
|
14042
|
+
prompt: isZh ? ZH_PROMPT : EN_PROMPT,
|
|
14043
|
+
builtinId: CHART_CAPABILITY_SKILL_ID
|
|
14044
|
+
};
|
|
14045
|
+
}
|
|
14046
|
+
function getChartMenuLine(locale) {
|
|
14047
|
+
const skill = getChartCapabilitySkill(locale);
|
|
14048
|
+
const isZh = locale.startsWith("zh");
|
|
14049
|
+
const guidance = isZh ? "\u7528\u6237\u660E\u786E\u8981\u6C42\u56FE\u8868\u3001\u753B\u56FE\u3001\u5360\u6BD4\u3001\u8D8B\u52BF\u3001\u5206\u5E03\u3001\u997C\u56FE\u3001\u67F1\u72B6\u56FE\u3001\u6298\u7EBF\u56FE\u6216\u70ED\u529B\u56FE\u65F6\u4F18\u5148\u6FC0\u6D3B\uFF1B\u4E0D\u8981\u8F93\u51FA Python/JS \u7ED8\u56FE\u4EE3\u7801" : "Activate first when the user explicitly asks for charts, visualization, ratios, trends, distributions, pie, bar, line, or heatmap charts; do not output Python/JS chart code";
|
|
14050
|
+
return formatSkillMenuLine({
|
|
14051
|
+
id: skill.id,
|
|
14052
|
+
name: skill.name,
|
|
14053
|
+
description: skill.description,
|
|
14054
|
+
guidance
|
|
14055
|
+
});
|
|
14056
|
+
}
|
|
14057
|
+
function buildSkillMenuWithBuiltinChart(baseMenu, locale = "zh-CN", allowedTools) {
|
|
14058
|
+
if (allowedTools && !allowedTools.includes(CHART_CAPABILITY_ANALYSIS_TOOLS[0])) return baseMenu ?? null;
|
|
14059
|
+
if (baseMenu?.includes(CHART_CAPABILITY_SKILL_ID)) return baseMenu;
|
|
14060
|
+
const chartLine = getChartMenuLine(locale);
|
|
14061
|
+
return appendSkillMenuLines(baseMenu, [chartLine]) ?? "";
|
|
14062
|
+
}
|
|
14063
|
+
function getSkillConfigWithBuiltinChart(id, locale = "zh-CN", getSkillConfig) {
|
|
14064
|
+
if (id === CHART_CAPABILITY_SKILL_ID) return getChartCapabilitySkill(locale);
|
|
14065
|
+
return getSkillConfig(id);
|
|
14066
|
+
}
|
|
14067
|
+
var ZH_PROMPT = `\u4F60\u662F ChatLab \u7ED8\u56FE\u52A9\u624B\u3002\u672C\u8F6E\u7528\u6237\u5E0C\u671B\u4F60\u5728\u56DE\u7B54\u91CC\u81EA\u7136\u5D4C\u5165\u4E00\u5F20\u6216\u591A\u5F20\u56FE\u8868\u3002
|
|
14068
|
+
|
|
14069
|
+
\u4F60\u5FC5\u987B\u901A\u8FC7 render_chart \u5DE5\u5177\u751F\u6210\u56FE\u8868\u3002\u4E0D\u8981\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001Canvas\u3001ECharts option \u6216\u4EFB\u4F55\u6E32\u67D3\u4EE3\u7801\u3002
|
|
14070
|
+
|
|
14071
|
+
\u786C\u6027\u89C4\u5219\uFF1A
|
|
14072
|
+
1. \u7B2C\u4E00\u6B21\u5199 SQL \u524D\u5FC5\u987B\u5148\u8C03\u7528 get_schema\u3002\u7981\u6B62\u731C\u6D4B\u8868\u540D\u3001\u5B57\u6BB5\u540D\u6216\u65F6\u95F4\u5B57\u6BB5\u3002
|
|
14073
|
+
2. \u201C\u6700\u8FD1\u201D\u201C\u5230\u73B0\u5728\u201D\u201C\u5230\u6700\u8FD1\u201D\u5FC5\u987B\u7528\u6570\u636E\u4E2D\u7684 MAX(ts) \u6216\u7B49\u4EF7\u5B57\u6BB5\u786E\u5B9A\u7ED3\u675F\u65E5\u671F\uFF1B\u4E0D\u8981\u624B\u7B97\u6216\u81C6\u6D4B\u65E5\u671F\u3002
|
|
14074
|
+
3. ChatLab \u7684 message.ts \u662F\u79D2\u7EA7 Unix \u65F6\u95F4\u6233\uFF0C\u4F7F\u7528 date(ts, 'unixepoch', 'localtime')\uFF1B\u7981\u6B62\u5199 ts/1000\u3002
|
|
14075
|
+
4. \u201C\u6700\u8FD1\u7684 N \u4EBA/\u6210\u5458\u201D\u5FC5\u987B\u5148\u7528\u6570\u636E\u5B9A\u4E49\u5E76\u7B5B\u9009\u51FA N \u4E2A\u6210\u5458\uFF0C\u518D\u53EA\u7EDF\u8BA1\u8FD9\u4E9B\u6210\u5458\u3002
|
|
14076
|
+
5. \u6298\u7EBF\u56FE\u6709\u591A\u6761\u7EBF\u65F6\uFF0C\u6BCF\u6761\u7EBF\u5FC5\u987B\u6709\u660E\u786E series \u5B57\u6BB5\u542B\u4E49\uFF1B\u6309\u65E5\u671F\u7EDF\u8BA1\u65F6\u5E94\u8865\u9F50\u65E5\u671F \xD7 series \u7684 0 \u503C\uFF0C\u907F\u514D\u7F3A\u5931\u65E5\u671F\u5BFC\u81F4\u6298\u7EBF\u65AD\u88C2\u6216\u8BEF\u8FDE\u3002
|
|
14077
|
+
6. \u5DE5\u5177\u5931\u8D25\u3001SQL \u4FEE\u6B63\u3001schema \u63A2\u7D22\u8FC7\u7A0B\u4E0D\u8981\u5199\u8FDB\u6700\u7EC8\u56DE\u7B54\uFF1B\u6700\u7EC8\u53EA\u4FDD\u7559\u56FE\u8868\u548C\u7B80\u77ED\u7ED3\u8BBA\u3002
|
|
14078
|
+
7. \u56FE\u8868\u89E3\u91CA\u53EA\u80FD\u63CF\u8FF0\u6570\u636E\u76F4\u63A5\u652F\u6301\u7684\u8D8B\u52BF\u3001\u5CF0\u503C\u3001\u4F4E\u8C37\u3001\u5DEE\u5F02\u548C\u540C\u6B65\u6027\uFF0C\u7981\u6B62\u5938\u5F20\u62DF\u4EBA\u5316\u6216\u65E0\u6CD5\u4ECE\u56FE\u4E2D\u9A8C\u8BC1\u7684\u5173\u7CFB\u5224\u65AD\u3002
|
|
14079
|
+
|
|
14080
|
+
\u5DE5\u4F5C\u6D41\u7A0B\uFF1A
|
|
14081
|
+
1. \u8C03\u7528 get_schema\u3002
|
|
14082
|
+
2. \u6839\u636E schema \u548C\u7528\u6237\u8981\u6C42\u786E\u5B9A\u7EDF\u8BA1\u5BF9\u8C61\u3001\u65F6\u95F4\u8303\u56F4\u3001\u7EF4\u5EA6\u3001\u6307\u6807\u548C\u56FE\u8868\u7C7B\u578B\u3002
|
|
14083
|
+
3. \u5FC5\u8981\u65F6\u7528\u53EA\u8BFB SQL \u5728 render_chart \u4E2D\u5B8C\u6210\u6210\u5458\u7B5B\u9009\u3001\u65F6\u95F4\u8303\u56F4\u786E\u8BA4\u3001\u805A\u5408\u548C\u8865\u96F6\u3002
|
|
14084
|
+
4. \u8C03\u7528 render_chart\uFF0C\u63D0\u4EA4\u53EA\u8BFB SQL \u548C ChartSpec v1\u3002
|
|
14085
|
+
5. \u56FE\u8868\u751F\u6210\u540E\uFF0C\u7528 1-3 \u53E5\u7B80\u6D01\u6587\u5B57\u89E3\u91CA\u7ED3\u8BBA\u3002\u7528\u6237\u8981\u6C42\u591A\u5F20\u56FE\u65F6\uFF0C\u53EF\u4EE5\u591A\u6B21\u8C03\u7528 render_chart\u3002
|
|
14086
|
+
|
|
14087
|
+
\u5E38\u7528\u8BED\u3001\u53E3\u5934\u7985\u3001\u9AD8\u9891\u77ED\u53E5\u7C7B\u56FE\u8868\u5FC5\u987B\u6392\u9664\u975E\u771F\u4EBA\u6587\u672C\uFF1A\u53D1\u9001\u8005\u4E3A\u7CFB\u7EDF\u6D88\u606F\u3001\u5A92\u4F53\u5360\u4F4D\uFF08\u5982 [\u8868\u60C5\u5305]\u3001[\u56FE\u7247]\u3001[\u8BED\u97F3]\u3001[\u89C6\u9891]\u3001[\u6587\u4EF6]\u3001[\u94FE\u63A5]\u3001[\u7EA2\u5305]\u3001[\u8F6C\u8D26]\uFF09\u4EE5\u53CA\u64A4\u56DE/\u5220\u9664\u63D0\u793A\u90FD\u4E0D\u80FD\u8FDB\u5165\u7EDF\u8BA1\u3002
|
|
14088
|
+
|
|
14089
|
+
ChartSpec v1 \u652F\u6301\uFF1A
|
|
14090
|
+
- bar: encoding.x + encoding.y
|
|
14091
|
+
- line: encoding.x + encoding.y\uFF0C\u53EF\u9009 encoding.series \u8868\u793A\u6BCF\u6761\u7EBF\u7684\u542B\u4E49
|
|
14092
|
+
- pie: encoding.label + encoding.value
|
|
14093
|
+
- heatmap: encoding.x + encoding.y + encoding.value
|
|
14094
|
+
|
|
14095
|
+
ChartSpec \u793A\u4F8B\uFF1A
|
|
14096
|
+
{
|
|
14097
|
+
"version": 1,
|
|
14098
|
+
"type": "line",
|
|
14099
|
+
"title": "\u6700\u8FD1 30 \u5929\u6210\u5458\u53D1\u8A00\u8D8B\u52BF",
|
|
14100
|
+
"encoding": { "x": "day", "y": "msg_count", "series": "member_name" },
|
|
14101
|
+
"unit": "\u6761"
|
|
14102
|
+
}
|
|
14103
|
+
|
|
14104
|
+
\u7528\u6237\u660E\u786E\u8981\u6C42\u56FE\u8868\u65F6\u5FC5\u987B\u5C1D\u8BD5\u751F\u6210\u3002\u7528\u6237\u6CA1\u6709\u660E\u786E\u8981\u6C42\u65F6\uFF0C\u53EA\u6709\u6392\u540D\u3001\u8D8B\u52BF\u3001\u5206\u5E03\u3001\u5360\u6BD4\u6216\u4E8C\u7EF4\u5BC6\u5EA6\u660E\u663E\u66F4\u6E05\u695A\u65F6\u624D\u4E3B\u52A8\u751F\u6210\uFF0C\u4E14\u9ED8\u8BA4\u6700\u591A\u4E00\u5F20\u3002`;
|
|
14105
|
+
var EN_PROMPT = `You are the ChatLab Chart Assistant. In this turn, the user wants one or more charts embedded naturally in the answer.
|
|
14106
|
+
|
|
14107
|
+
You must generate charts through the render_chart tool. Do not output HTML, JavaScript, SVG, Canvas, ECharts options, or rendering code.
|
|
14108
|
+
|
|
14109
|
+
Hard rules:
|
|
14110
|
+
1. Always call get_schema before writing the first SQL query. Do not guess table names, field names, or timestamp fields.
|
|
14111
|
+
2. For "latest", "until now", or "through the latest date", derive the end date from MAX(ts) or the equivalent timestamp field in the data. Do not hand-calculate or assume dates.
|
|
14112
|
+
3. ChatLab message.ts is a Unix timestamp in seconds. Use date(ts, 'unixepoch', 'localtime'); never write ts/1000.
|
|
14113
|
+
4. For "latest N members" or "recent N people", first define and select those N members from the data, then count only those members.
|
|
14114
|
+
5. For multi-series line charts, every line must have an explicit series field. For daily counts, fill the date x series grid with zero values so missing days do not break or mislead the line.
|
|
14115
|
+
6. Do not include failed SQL attempts, schema exploration, or retry reasoning in the final answer. Final answer should contain only the chart and a short conclusion.
|
|
14116
|
+
7. Explain only trends, peaks, lows, differences, and synchrony directly supported by chart data. Do not make exaggerated personality or relationship claims.
|
|
14117
|
+
|
|
14118
|
+
Workflow:
|
|
14119
|
+
1. Call get_schema.
|
|
14120
|
+
2. Derive the target members, time range, dimensions, metrics, and chart type from schema and the user request.
|
|
14121
|
+
3. When needed, use read-only SQL inside render_chart to select members, determine time range, aggregate data, and fill zero rows.
|
|
14122
|
+
4. Call render_chart with read-only SQL and ChartSpec v1.
|
|
14123
|
+
5. After the chart is generated, explain the key finding in 1-3 concise sentences. If the user asks for multiple charts, call render_chart multiple times.
|
|
14124
|
+
|
|
14125
|
+
For catchphrase, common phrase, or frequent short-text charts, exclude non-human text from the SQL: system-message senders, media placeholders such as [Sticker], [Image], [Photo], [Voice], [Video], [File], [Link], and recall/deletion notices must not be counted.
|
|
14126
|
+
|
|
14127
|
+
ChartSpec v1 supports:
|
|
14128
|
+
- bar: encoding.x + encoding.y
|
|
14129
|
+
- line: encoding.x + encoding.y, optional encoding.series for the meaning of each line
|
|
14130
|
+
- pie: encoding.label + encoding.value
|
|
14131
|
+
- heatmap: encoding.x + encoding.y + encoding.value
|
|
14132
|
+
|
|
14133
|
+
ChartSpec example:
|
|
14134
|
+
{
|
|
14135
|
+
"version": 1,
|
|
14136
|
+
"type": "line",
|
|
14137
|
+
"title": "Member message trend in the last 30 days",
|
|
14138
|
+
"encoding": { "x": "day", "y": "msg_count", "series": "member_name" },
|
|
14139
|
+
"unit": "messages"
|
|
14140
|
+
}
|
|
14141
|
+
|
|
14142
|
+
When the user explicitly asks for charts, you must try to generate them. If the user does not explicitly ask, add at most one chart only when ranking, trend, distribution, ratio, or two-dimensional density is clearly easier to understand visually.`;
|
|
14143
|
+
|
|
14144
|
+
// ../../packages/node-runtime/src/ai/chart-schema-gate.ts
|
|
14145
|
+
var CHART_SCHEMA_REQUIRED_MESSAGE = "Error: Call get_schema before render_chart. Do not guess table names, fields, or timestamp units.";
|
|
14146
|
+
function createChartSchemaGateState() {
|
|
14147
|
+
return { schemaSeen: false };
|
|
14148
|
+
}
|
|
14149
|
+
function wrapWithChartSchemaGate(tool, state) {
|
|
14150
|
+
const originalExecute = tool.execute;
|
|
14151
|
+
return {
|
|
14152
|
+
...tool,
|
|
14153
|
+
execute: async (toolCallId, params, signal, onUpdate) => {
|
|
14154
|
+
if (tool.name === "render_chart" && !state.schemaSeen) {
|
|
14155
|
+
return {
|
|
14156
|
+
content: [{ type: "text", text: CHART_SCHEMA_REQUIRED_MESSAGE }],
|
|
14157
|
+
details: null
|
|
14158
|
+
};
|
|
14159
|
+
}
|
|
14160
|
+
const result = await originalExecute(toolCallId, params, signal, onUpdate);
|
|
14161
|
+
if (tool.name === "get_schema") {
|
|
14162
|
+
state.schemaSeen = true;
|
|
14163
|
+
}
|
|
14164
|
+
return result;
|
|
14165
|
+
}
|
|
14166
|
+
};
|
|
14167
|
+
}
|
|
14168
|
+
|
|
13766
14169
|
// ../../packages/node-runtime/src/ai/compression/compressor.ts
|
|
13767
14170
|
var DEFAULT_CONTEXT_WINDOW = 128e3;
|
|
13768
14171
|
var INITIAL_COMPRESSION_PROMPT = `You are a context compression assistant. Compress the conversation below into a structured summary.
|
|
@@ -14542,6 +14945,11 @@ import {
|
|
|
14542
14945
|
streamSimple as defaultStreamSimple,
|
|
14543
14946
|
clampThinkingLevel
|
|
14544
14947
|
} from "@earendil-works/pi-ai";
|
|
14948
|
+
|
|
14949
|
+
// ../../packages/node-runtime/src/ai/agent/constants.ts
|
|
14950
|
+
var DEFAULT_MAX_TOOL_ROUNDS = 10;
|
|
14951
|
+
|
|
14952
|
+
// ../../packages/node-runtime/src/ai/agent/core.ts
|
|
14545
14953
|
function createEmptyPiUsage() {
|
|
14546
14954
|
return {
|
|
14547
14955
|
input: 0,
|
|
@@ -14584,7 +14992,7 @@ async function runAgentCore(options) {
|
|
|
14584
14992
|
tools,
|
|
14585
14993
|
history,
|
|
14586
14994
|
userMessage,
|
|
14587
|
-
maxToolRounds =
|
|
14995
|
+
maxToolRounds = DEFAULT_MAX_TOOL_ROUNDS,
|
|
14588
14996
|
abortSignal,
|
|
14589
14997
|
steerMessage = "Please provide your final answer based on the information gathered.",
|
|
14590
14998
|
onEvent,
|
|
@@ -15222,6 +15630,19 @@ var zh_CN_default = {
|
|
|
15222
15630
|
days: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E",
|
|
15223
15631
|
top_n: "\u8FD4\u56DE\u524D\u591A\u5C11\u4E2A\u5173\u952E\u8BCD"
|
|
15224
15632
|
}
|
|
15633
|
+
},
|
|
15634
|
+
get_schema: {
|
|
15635
|
+
desc: "\u67E5\u770B\u804A\u5929\u6570\u636E\u5E93\u8868\u7ED3\u6784\u3002\u7ED8\u56FE\u6216\u81EA\u5B9A\u4E49 SQL \u524D\u5E94\u5148\u7528\u5B83\u786E\u8BA4\u8868\u540D\u548C\u5B57\u6BB5\u540D\u3002",
|
|
15636
|
+
params: {}
|
|
15637
|
+
},
|
|
15638
|
+
render_chart: {
|
|
15639
|
+
desc: "\u6839\u636E\u53EA\u8BFB SQL \u548C ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u56FE\u8868\u3002\u652F\u6301 bar\u3001line\u3001pie\u3001heatmap\u3002\u7981\u6B62\u8F93\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u4EE3\u7801\u3002",
|
|
15640
|
+
params: {
|
|
15641
|
+
sql: "\u53EA\u8BFB SELECT \u6216 WITH SELECT SQL\u3002\u5FC5\u987B\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u5B57\u6BB5\u3002",
|
|
15642
|
+
params: "SQL \u547D\u540D\u53C2\u6570\u5BF9\u8C61\uFF1B\u4E0D\u9700\u8981\u53C2\u6570\u65F6\u4F20\u7A7A\u5BF9\u8C61\u3002",
|
|
15643
|
+
chartSpec: "ChartSpec v1\uFF0C\u5305\u542B version\u3001type\u3001title\u3001encoding\u3002",
|
|
15644
|
+
maxRows: "\u56FE\u8868\u67E5\u8BE2\u6700\u5927\u884C\u6570\uFF0C\u9ED8\u8BA4 1000\u3002"
|
|
15645
|
+
}
|
|
15225
15646
|
}
|
|
15226
15647
|
},
|
|
15227
15648
|
agent: {
|
|
@@ -15544,6 +15965,19 @@ Returned summaries are brief descriptions of each session, helping quickly locat
|
|
|
15544
15965
|
days: "Number of recent days to analyze",
|
|
15545
15966
|
top_n: "Number of top keywords to return"
|
|
15546
15967
|
}
|
|
15968
|
+
},
|
|
15969
|
+
get_schema: {
|
|
15970
|
+
desc: "Inspect the chat database schema. Use it before charting or custom SQL when table or field names are uncertain.",
|
|
15971
|
+
params: {}
|
|
15972
|
+
},
|
|
15973
|
+
render_chart: {
|
|
15974
|
+
desc: "Generate a native ChatLab chart from read-only SQL and ChartSpec v1. Supports bar, line, pie, and heatmap. Do not output HTML, JavaScript, SVG, ECharts options, or rendering code.",
|
|
15975
|
+
params: {
|
|
15976
|
+
sql: "Read-only SELECT or WITH SELECT SQL. It must return fields referenced by ChartSpec encoding.",
|
|
15977
|
+
params: "Named SQL parameters. Use an empty object when no parameters are needed.",
|
|
15978
|
+
chartSpec: "ChartSpec v1 with version, type, title, and encoding.",
|
|
15979
|
+
maxRows: "Maximum chart query rows. Default 1000."
|
|
15980
|
+
}
|
|
15547
15981
|
}
|
|
15548
15982
|
},
|
|
15549
15983
|
// ===== AI Agent system prompts =====
|
|
@@ -15862,6 +16296,19 @@ var ja_JP_default = {
|
|
|
15862
16296
|
days: "\u76F4\u8FD1\u4F55\u65E5\u9593\u306E\u30C7\u30FC\u30BF\u3092\u96C6\u8A08\u3059\u308B\u304B",
|
|
15863
16297
|
top_n: "\u4E0A\u4F4D\u4F55\u500B\u306E\u30AD\u30FC\u30EF\u30FC\u30C9\u3092\u8FD4\u5374\u3059\u308B\u304B"
|
|
15864
16298
|
}
|
|
16299
|
+
},
|
|
16300
|
+
get_schema: {
|
|
16301
|
+
desc: "\u30C1\u30E3\u30C3\u30C8\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30B9\u30AD\u30FC\u30DE\u3092\u78BA\u8A8D\u3057\u307E\u3059\u3002\u30C1\u30E3\u30FC\u30C8\u4F5C\u6210\u3084\u30AB\u30B9\u30BF\u30E0 SQL \u306E\u524D\u306B\u30C6\u30FC\u30D6\u30EB\u540D\u3068\u30D5\u30A3\u30FC\u30EB\u30C9\u540D\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
16302
|
+
params: {}
|
|
16303
|
+
},
|
|
16304
|
+
render_chart: {
|
|
16305
|
+
desc: "\u8AAD\u307F\u53D6\u308A\u5C02\u7528 SQL \u3068 ChartSpec v1 \u304B\u3089 ChatLab \u30CD\u30A4\u30C6\u30A3\u30D6\u30C1\u30E3\u30FC\u30C8\u3092\u751F\u6210\u3057\u307E\u3059\u3002bar\u3001line\u3001pie\u3001heatmap \u3092\u30B5\u30DD\u30FC\u30C8\u3057\u307E\u3059\u3002HTML\u3001JavaScript\u3001SVG\u3001ECharts option\u3001\u63CF\u753B\u30B3\u30FC\u30C9\u306F\u51FA\u529B\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002",
|
|
16306
|
+
params: {
|
|
16307
|
+
sql: "\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u306E SELECT \u307E\u305F\u306F WITH SELECT SQL\u3002ChartSpec encoding \u3067\u53C2\u7167\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002",
|
|
16308
|
+
params: "SQL \u306E\u540D\u524D\u4ED8\u304D\u30D1\u30E9\u30E1\u30FC\u30BF\u3002\u4E0D\u8981\u306A\u5834\u5408\u306F\u7A7A\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u6E21\u3057\u307E\u3059\u3002",
|
|
16309
|
+
chartSpec: "version\u3001type\u3001title\u3001encoding \u3092\u542B\u3080 ChartSpec v1\u3002",
|
|
16310
|
+
maxRows: "\u30C1\u30E3\u30FC\u30C8\u30AF\u30A8\u30EA\u306E\u6700\u5927\u884C\u6570\u3002\u30C7\u30D5\u30A9\u30EB\u30C8\u306F 1000\u3002"
|
|
16311
|
+
}
|
|
15865
16312
|
}
|
|
15866
16313
|
},
|
|
15867
16314
|
agent: {
|
|
@@ -16181,6 +16628,19 @@ var zh_TW_default = {
|
|
|
16181
16628
|
days: "\u7D71\u8A08\u6700\u8FD1\u591A\u5C11\u5929\u7684\u8CC7\u6599",
|
|
16182
16629
|
top_n: "\u56DE\u50B3\u524D\u591A\u5C11\u500B\u95DC\u9375\u8A5E"
|
|
16183
16630
|
}
|
|
16631
|
+
},
|
|
16632
|
+
get_schema: {
|
|
16633
|
+
desc: "\u67E5\u770B\u804A\u5929\u8CC7\u6599\u5EAB\u8868\u7D50\u69CB\u3002\u7E6A\u5716\u6216\u81EA\u8A02 SQL \u524D\u61C9\u5148\u7528\u5B83\u78BA\u8A8D\u8868\u540D\u548C\u6B04\u4F4D\u540D\u3002",
|
|
16634
|
+
params: {}
|
|
16635
|
+
},
|
|
16636
|
+
render_chart: {
|
|
16637
|
+
desc: "\u6839\u64DA\u552F\u8B80 SQL \u548C ChartSpec v1 \u751F\u6210 ChatLab \u539F\u751F\u5716\u8868\u3002\u652F\u63F4 bar\u3001line\u3001pie\u3001heatmap\u3002\u7981\u6B62\u8F38\u51FA HTML\u3001JavaScript\u3001SVG\u3001ECharts option \u6216\u6E32\u67D3\u7A0B\u5F0F\u78BC\u3002",
|
|
16638
|
+
params: {
|
|
16639
|
+
sql: "\u552F\u8B80 SELECT \u6216 WITH SELECT SQL\u3002\u5FC5\u9808\u8FD4\u56DE ChartSpec encoding \u4E2D\u5F15\u7528\u7684\u6B04\u4F4D\u3002",
|
|
16640
|
+
params: "SQL \u547D\u540D\u53C3\u6578\u7269\u4EF6\uFF1B\u4E0D\u9700\u8981\u53C3\u6578\u6642\u50B3\u7A7A\u7269\u4EF6\u3002",
|
|
16641
|
+
chartSpec: "ChartSpec v1\uFF0C\u5305\u542B version\u3001type\u3001title\u3001encoding\u3002",
|
|
16642
|
+
maxRows: "\u5716\u8868\u67E5\u8A62\u6700\u5927\u884C\u6578\uFF0C\u9810\u8A2D 1000\u3002"
|
|
16643
|
+
}
|
|
16184
16644
|
}
|
|
16185
16645
|
},
|
|
16186
16646
|
agent: {
|
|
@@ -18925,6 +19385,7 @@ export {
|
|
|
18925
19385
|
getRelationshipStats,
|
|
18926
19386
|
getLanguagePreferenceAnalysis,
|
|
18927
19387
|
isNewerStableVersion,
|
|
19388
|
+
buildChartPayload,
|
|
18928
19389
|
POS_TAG_DEFINITIONS,
|
|
18929
19390
|
BUILTIN_TOOL_CATALOG,
|
|
18930
19391
|
BUILTIN_PROVIDERS,
|
|
@@ -18963,14 +19424,23 @@ export {
|
|
|
18963
19424
|
AIConversationManager,
|
|
18964
19425
|
initTokenizer,
|
|
18965
19426
|
countMessagesTokens,
|
|
18966
|
-
SkillManager,
|
|
18967
19427
|
SkillManagerCore,
|
|
19428
|
+
SkillManager,
|
|
18968
19429
|
createActivateSkillTool,
|
|
19430
|
+
CHART_CAPABILITY_CORE_TOOLS,
|
|
19431
|
+
getAllowedBuiltinToolsForChartAutoSkill,
|
|
19432
|
+
resolveChartRuntimeForRequest,
|
|
19433
|
+
getChartCapabilitySkill,
|
|
19434
|
+
buildSkillMenuWithBuiltinChart,
|
|
19435
|
+
getSkillConfigWithBuiltinChart,
|
|
19436
|
+
createChartSchemaGateState,
|
|
19437
|
+
wrapWithChartSchemaGate,
|
|
18969
19438
|
checkAndCompress,
|
|
18970
19439
|
createCompressionLlmAdapter,
|
|
18971
19440
|
getDefaultRulesForLocale,
|
|
18972
19441
|
mergeRulesForLocale,
|
|
18973
19442
|
applyPreprocessingPipeline,
|
|
19443
|
+
DEFAULT_MAX_TOOL_ROUNDS,
|
|
18974
19444
|
runAgentCore,
|
|
18975
19445
|
AgentEventHandler,
|
|
18976
19446
|
buildSystemPrompt,
|
|
@@ -19005,4 +19475,4 @@ export {
|
|
|
19005
19475
|
createDatabaseManagerAdapter,
|
|
19006
19476
|
MergeSessionCache
|
|
19007
19477
|
};
|
|
19008
|
-
//# sourceMappingURL=chunk-
|
|
19478
|
+
//# sourceMappingURL=chunk-4OMV4VNH.mjs.map
|