@kwirthmagnify/kwirth-plugin-pinocchio 0.2.10 → 0.2.12
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/back.js +50 -573
- package/front.js +94 -404
- package/package.json +1 -1
package/back.js
CHANGED
|
@@ -11262,544 +11262,8 @@ var kindsAvailable = ["Pod", "Deployment", "DaemonSet", "StatefulSet", "ReplicaS
|
|
|
11262
11262
|
|
|
11263
11263
|
// src/back/index.ts
|
|
11264
11264
|
var import_kwirth_common_ai = __toESM(require_kwirth_common_ai(), 1);
|
|
11265
|
-
var import_back2 = __toESM(require_back(), 1);
|
|
11266
|
-
var import_back3 = __toESM(require_back(), 1);
|
|
11267
|
-
|
|
11268
|
-
// src/back/Tools.ts
|
|
11269
11265
|
var import_back = __toESM(require_back(), 1);
|
|
11270
|
-
var
|
|
11271
|
-
var import_util = require("util");
|
|
11272
|
-
var execAsync = (0, import_util.promisify)(import_child_process.exec);
|
|
11273
|
-
function mapToJson(data) {
|
|
11274
|
-
if (data instanceof Map) {
|
|
11275
|
-
const obj = {};
|
|
11276
|
-
for (const [key, value] of data.entries()) {
|
|
11277
|
-
obj[String(key)] = mapToJson(value);
|
|
11278
|
-
}
|
|
11279
|
-
return obj;
|
|
11280
|
-
}
|
|
11281
|
-
if (Array.isArray(data)) {
|
|
11282
|
-
return data.map(mapToJson);
|
|
11283
|
-
}
|
|
11284
|
-
if (data !== null && typeof data === "object") {
|
|
11285
|
-
const newObj = {};
|
|
11286
|
-
for (const key of Object.keys(data)) {
|
|
11287
|
-
newObj[key] = mapToJson(data[key]);
|
|
11288
|
-
}
|
|
11289
|
-
return newObj;
|
|
11290
|
-
}
|
|
11291
|
-
return data;
|
|
11292
|
-
}
|
|
11293
|
-
var createTools = (context) => {
|
|
11294
|
-
return {
|
|
11295
|
-
// ── CLUSTER CONFIG ───────────────────────────────────────────────────
|
|
11296
|
-
get_node_data: (0, import_back.tool)({
|
|
11297
|
-
description: "Returns configuration info about all Kubernetes nodes (name, IP). Configuration only \u2014 not workload or usage data.",
|
|
11298
|
-
inputSchema: import_back.z.object({}),
|
|
11299
|
-
execute: async () => {
|
|
11300
|
-
context.trace("get_node_data", {});
|
|
11301
|
-
return mapToJson(context.nodes);
|
|
11302
|
-
}
|
|
11303
|
-
}),
|
|
11304
|
-
get_cluster_data: (0, import_back.tool)({
|
|
11305
|
-
description: "Returns general cluster info: name, flavour (AKS/EKS/GKE/k3s/k3d), total vCPUs, total memory, node count and readiness status.",
|
|
11306
|
-
inputSchema: import_back.z.object({}),
|
|
11307
|
-
execute: async () => {
|
|
11308
|
-
context.trace("get_cluster_data", {});
|
|
11309
|
-
try {
|
|
11310
|
-
const resp = await context.clusterInfo.coreApi.listNode();
|
|
11311
|
-
return {
|
|
11312
|
-
name: context.clusterInfo.name,
|
|
11313
|
-
flavour: context.clusterInfo.flavour,
|
|
11314
|
-
vcpus: context.clusterInfo.vcpus,
|
|
11315
|
-
memoryGB: Math.round(context.clusterInfo.memory / 1024 / 1024 / 1024 * 100) / 100,
|
|
11316
|
-
nodeCount: resp.items.length,
|
|
11317
|
-
nodes: resp.items.map((n) => ({
|
|
11318
|
-
name: n.metadata?.name,
|
|
11319
|
-
cpu: n.status?.capacity?.["cpu"],
|
|
11320
|
-
memoryKi: n.status?.capacity?.["memory"],
|
|
11321
|
-
ready: n.status?.conditions?.find((c) => c.type === "Ready")?.status === "True",
|
|
11322
|
-
unschedulable: n.spec?.unschedulable ?? false
|
|
11323
|
-
}))
|
|
11324
|
-
};
|
|
11325
|
-
} catch (err) {
|
|
11326
|
-
return { error: err.message ?? String(err) };
|
|
11327
|
-
}
|
|
11328
|
-
}
|
|
11329
|
-
}),
|
|
11330
|
-
get_workload_data: (0, import_back.tool)({
|
|
11331
|
-
description: "Returns all workloads in the cluster: deployments, statefulsets, daemonsets, pods and services. Optionally filter by namespace.",
|
|
11332
|
-
inputSchema: import_back.z.object({
|
|
11333
|
-
namespace: import_back.z.string().optional().describe("Namespace to filter results (omit for all namespaces)")
|
|
11334
|
-
}),
|
|
11335
|
-
execute: async ({ namespace }) => {
|
|
11336
|
-
context.trace("get_workload_data", { namespace: namespace ?? "*" });
|
|
11337
|
-
try {
|
|
11338
|
-
const [deploymentsResp, statefulSetsResp, daemonSetsResp, podsResp, servicesResp] = await Promise.all([
|
|
11339
|
-
namespace ? context.clusterInfo.appsApi.listNamespacedDeployment({ namespace }) : context.clusterInfo.appsApi.listDeploymentForAllNamespaces(),
|
|
11340
|
-
namespace ? context.clusterInfo.appsApi.listNamespacedStatefulSet({ namespace }) : context.clusterInfo.appsApi.listStatefulSetForAllNamespaces(),
|
|
11341
|
-
namespace ? context.clusterInfo.appsApi.listNamespacedDaemonSet({ namespace }) : context.clusterInfo.appsApi.listDaemonSetForAllNamespaces(),
|
|
11342
|
-
namespace ? context.clusterInfo.coreApi.listNamespacedPod({ namespace }) : context.clusterInfo.coreApi.listPodForAllNamespaces(),
|
|
11343
|
-
namespace ? context.clusterInfo.coreApi.listNamespacedService({ namespace }) : context.clusterInfo.coreApi.listServiceForAllNamespaces()
|
|
11344
|
-
]);
|
|
11345
|
-
return {
|
|
11346
|
-
deployments: deploymentsResp.items.map((d) => ({
|
|
11347
|
-
name: d.metadata?.name,
|
|
11348
|
-
namespace: d.metadata?.namespace,
|
|
11349
|
-
replicas: d.spec?.replicas,
|
|
11350
|
-
readyReplicas: d.status?.readyReplicas ?? 0,
|
|
11351
|
-
availableReplicas: d.status?.availableReplicas ?? 0
|
|
11352
|
-
})),
|
|
11353
|
-
statefulSets: statefulSetsResp.items.map((s) => ({
|
|
11354
|
-
name: s.metadata?.name,
|
|
11355
|
-
namespace: s.metadata?.namespace,
|
|
11356
|
-
replicas: s.spec?.replicas,
|
|
11357
|
-
readyReplicas: s.status?.readyReplicas ?? 0
|
|
11358
|
-
})),
|
|
11359
|
-
daemonSets: daemonSetsResp.items.map((d) => ({
|
|
11360
|
-
name: d.metadata?.name,
|
|
11361
|
-
namespace: d.metadata?.namespace,
|
|
11362
|
-
desired: d.status?.desiredNumberScheduled,
|
|
11363
|
-
ready: d.status?.numberReady
|
|
11364
|
-
})),
|
|
11365
|
-
pods: podsResp.items.map((p) => ({
|
|
11366
|
-
name: p.metadata?.name,
|
|
11367
|
-
namespace: p.metadata?.namespace,
|
|
11368
|
-
nodeName: p.spec?.nodeName,
|
|
11369
|
-
phase: p.status?.phase,
|
|
11370
|
-
ready: p.status?.conditions?.find((c) => c.type === "Ready")?.status === "True"
|
|
11371
|
-
})),
|
|
11372
|
-
services: servicesResp.items.map((s) => ({
|
|
11373
|
-
name: s.metadata?.name,
|
|
11374
|
-
namespace: s.metadata?.namespace,
|
|
11375
|
-
type: s.spec?.type,
|
|
11376
|
-
clusterIP: s.spec?.clusterIP
|
|
11377
|
-
}))
|
|
11378
|
-
};
|
|
11379
|
-
} catch (err) {
|
|
11380
|
-
return { error: err.message ?? String(err) };
|
|
11381
|
-
}
|
|
11382
|
-
}
|
|
11383
|
-
}),
|
|
11384
|
-
get_space_data: (0, import_back.tool)({
|
|
11385
|
-
description: "Returns all resources in a specific Kubernetes namespace: pods (with restart count), deployments, services, configmap names.",
|
|
11386
|
-
inputSchema: import_back.z.object({
|
|
11387
|
-
namespace: import_back.z.string().describe("Name of the namespace to retrieve data for")
|
|
11388
|
-
}),
|
|
11389
|
-
execute: async ({ namespace }) => {
|
|
11390
|
-
context.trace("get_space_data", { namespace });
|
|
11391
|
-
try {
|
|
11392
|
-
const [podsResp, deploymentsResp, servicesResp, configMapsResp] = await Promise.all([
|
|
11393
|
-
context.clusterInfo.coreApi.listNamespacedPod({ namespace }),
|
|
11394
|
-
context.clusterInfo.appsApi.listNamespacedDeployment({ namespace }),
|
|
11395
|
-
context.clusterInfo.coreApi.listNamespacedService({ namespace }),
|
|
11396
|
-
context.clusterInfo.coreApi.listNamespacedConfigMap({ namespace })
|
|
11397
|
-
]);
|
|
11398
|
-
return {
|
|
11399
|
-
namespace,
|
|
11400
|
-
pods: podsResp.items.map((p) => ({
|
|
11401
|
-
name: p.metadata?.name,
|
|
11402
|
-
phase: p.status?.phase,
|
|
11403
|
-
nodeName: p.spec?.nodeName,
|
|
11404
|
-
ready: p.status?.conditions?.find((c) => c.type === "Ready")?.status === "True",
|
|
11405
|
-
restartCount: p.status?.containerStatuses?.reduce((sum, cs) => sum + cs.restartCount, 0) ?? 0
|
|
11406
|
-
})),
|
|
11407
|
-
deployments: deploymentsResp.items.map((d) => ({
|
|
11408
|
-
name: d.metadata?.name,
|
|
11409
|
-
replicas: d.spec?.replicas,
|
|
11410
|
-
readyReplicas: d.status?.readyReplicas ?? 0,
|
|
11411
|
-
image: d.spec?.template?.spec?.containers?.[0]?.image
|
|
11412
|
-
})),
|
|
11413
|
-
services: servicesResp.items.map((s) => ({
|
|
11414
|
-
name: s.metadata?.name,
|
|
11415
|
-
type: s.spec?.type,
|
|
11416
|
-
clusterIP: s.spec?.clusterIP
|
|
11417
|
-
})),
|
|
11418
|
-
configMaps: configMapsResp.items.map((cm) => cm.metadata?.name)
|
|
11419
|
-
};
|
|
11420
|
-
} catch (err) {
|
|
11421
|
-
return { error: err.message ?? String(err) };
|
|
11422
|
-
}
|
|
11423
|
-
}
|
|
11424
|
-
}),
|
|
11425
|
-
// ── CURRENT USAGE ────────────────────────────────────────────────────
|
|
11426
|
-
get_cluster_usage: (0, import_back.tool)({
|
|
11427
|
-
description: "Returns current overall cluster resource usage: CPU%, memory%, network Mbps, total vCPUs and total memory GB.",
|
|
11428
|
-
inputSchema: import_back.z.object({}),
|
|
11429
|
-
execute: async () => {
|
|
11430
|
-
context.trace("get_cluster_usage", {});
|
|
11431
|
-
if (context.clusterMetrics.length === 0) return { error: "No metrics available yet" };
|
|
11432
|
-
const latest = context.clusterMetrics[context.clusterMetrics.length - 1];
|
|
11433
|
-
return {
|
|
11434
|
-
vcpus: latest.cluster.vcpus,
|
|
11435
|
-
memoryGB: Math.round(latest.cluster.memory / 1024 / 1024 / 1024 * 100) / 100,
|
|
11436
|
-
cpuUsagePercent: Math.round(latest.cluster.cpuUsage * 100) / 100,
|
|
11437
|
-
memoryUsagePercent: Math.round(latest.cluster.memoryUsage * 100) / 100,
|
|
11438
|
-
networkTxMbps: Math.round(latest.cluster.txmbps * 100) / 100,
|
|
11439
|
-
networkRxMbps: Math.round(latest.cluster.rxmbps * 100) / 100,
|
|
11440
|
-
metricsIntervalSeconds: latest.metricsInterval
|
|
11441
|
-
};
|
|
11442
|
-
}
|
|
11443
|
-
}),
|
|
11444
|
-
get_node_usage: (0, import_back.tool)({
|
|
11445
|
-
description: "Returns current CPU and memory usage for one node or all nodes from the latest metrics reading.",
|
|
11446
|
-
inputSchema: import_back.z.object({
|
|
11447
|
-
nodeName: import_back.z.string().optional().describe("Node name to filter (omit for all nodes)")
|
|
11448
|
-
}),
|
|
11449
|
-
execute: async ({ nodeName }) => {
|
|
11450
|
-
context.trace("get_node_usage", { nodeName: nodeName ?? "*" });
|
|
11451
|
-
if (context.clusterMetrics.length === 0) return { error: "No metrics available yet" };
|
|
11452
|
-
const latest = context.clusterMetrics[context.clusterMetrics.length - 1];
|
|
11453
|
-
const nodes = nodeName ? latest.nodes.filter((n) => n.name === nodeName) : latest.nodes;
|
|
11454
|
-
return nodes.map((node) => ({
|
|
11455
|
-
name: node.name,
|
|
11456
|
-
cpuMillicores: Math.round((node.summary?.cpu?.usageNanoCores ?? 0) / 1e6),
|
|
11457
|
-
memoryMB: Math.round((node.summary?.memory?.workingSetBytes ?? 0) / 1024 / 1024),
|
|
11458
|
-
networkRxMB: Math.round((node.summary?.network?.rxBytes ?? 0) / 1024 / 1024),
|
|
11459
|
-
networkTxMB: Math.round((node.summary?.network?.txBytes ?? 0) / 1024 / 1024),
|
|
11460
|
-
podCount: node.summary?.pods?.length ?? 0,
|
|
11461
|
-
timestamp: node.timestamp
|
|
11462
|
-
}));
|
|
11463
|
-
}
|
|
11464
|
-
}),
|
|
11465
|
-
get_deployment_usage: (0, import_back.tool)({
|
|
11466
|
-
description: "Returns current aggregated CPU and memory usage for all pods belonging to a specific deployment.",
|
|
11467
|
-
inputSchema: import_back.z.object({
|
|
11468
|
-
namespace: import_back.z.string().describe("Namespace of the deployment"),
|
|
11469
|
-
name: import_back.z.string().describe("Name of the deployment")
|
|
11470
|
-
}),
|
|
11471
|
-
execute: async ({ namespace, name }) => {
|
|
11472
|
-
context.trace("get_deployment_usage", { namespace, name });
|
|
11473
|
-
try {
|
|
11474
|
-
if (context.clusterMetrics.length === 0) return { error: "No metrics available yet" };
|
|
11475
|
-
const latest = context.clusterMetrics[context.clusterMetrics.length - 1];
|
|
11476
|
-
const deployResp = await context.clusterInfo.appsApi.readNamespacedDeployment({ name, namespace });
|
|
11477
|
-
const labelSelector = Object.entries(deployResp.spec?.selector?.matchLabels ?? {}).map(([k, v]) => `${k}=${v}`).join(",");
|
|
11478
|
-
const podsResp = await context.clusterInfo.coreApi.listNamespacedPod({ namespace, labelSelector });
|
|
11479
|
-
const podNames = new Set(podsResp.items.map((p) => p.metadata?.name));
|
|
11480
|
-
let totalCpuNanoCores = 0;
|
|
11481
|
-
let totalMemoryBytes = 0;
|
|
11482
|
-
let podCount = 0;
|
|
11483
|
-
for (const node of latest.nodes) {
|
|
11484
|
-
for (const pod of node.summary?.pods ?? []) {
|
|
11485
|
-
if (pod.podRef?.namespace === namespace && podNames.has(pod.podRef?.name)) {
|
|
11486
|
-
totalCpuNanoCores += pod.cpu?.usageNanoCores ?? 0;
|
|
11487
|
-
totalMemoryBytes += pod.memory?.workingSetBytes ?? 0;
|
|
11488
|
-
podCount++;
|
|
11489
|
-
}
|
|
11490
|
-
}
|
|
11491
|
-
}
|
|
11492
|
-
return {
|
|
11493
|
-
deployment: name,
|
|
11494
|
-
namespace,
|
|
11495
|
-
podCount,
|
|
11496
|
-
cpuMillicores: Math.round(totalCpuNanoCores / 1e6),
|
|
11497
|
-
memoryMB: Math.round(totalMemoryBytes / 1024 / 1024),
|
|
11498
|
-
timestamp: latest.nodes[0]?.timestamp
|
|
11499
|
-
};
|
|
11500
|
-
} catch (err) {
|
|
11501
|
-
return { error: err.message ?? String(err) };
|
|
11502
|
-
}
|
|
11503
|
-
}
|
|
11504
|
-
}),
|
|
11505
|
-
// ── HISTORICAL USAGE ─────────────────────────────────────────────────
|
|
11506
|
-
get_prev_cluster_usage: (0, import_back.tool)({
|
|
11507
|
-
description: "Returns historical overall cluster usage over the last N metrics readings (CPU%, memory%, network Mbps).",
|
|
11508
|
-
inputSchema: import_back.z.object({
|
|
11509
|
-
count: import_back.z.number().optional().describe("Number of historical readings to return (default: 5)")
|
|
11510
|
-
}),
|
|
11511
|
-
execute: async ({ count = 5 }) => {
|
|
11512
|
-
context.trace("get_prev_cluster_usage", { count });
|
|
11513
|
-
if (context.clusterMetrics.length === 0) return { error: "No metrics available yet" };
|
|
11514
|
-
return context.clusterMetrics.slice(-count).map((reading) => ({
|
|
11515
|
-
vcpus: reading.cluster.vcpus,
|
|
11516
|
-
memoryGB: Math.round(reading.cluster.memory / 1024 / 1024 / 1024 * 100) / 100,
|
|
11517
|
-
cpuUsagePercent: Math.round(reading.cluster.cpuUsage * 100) / 100,
|
|
11518
|
-
memoryUsagePercent: Math.round(reading.cluster.memoryUsage * 100) / 100,
|
|
11519
|
-
networkTxMbps: Math.round(reading.cluster.txmbps * 100) / 100,
|
|
11520
|
-
networkRxMbps: Math.round(reading.cluster.rxmbps * 100) / 100
|
|
11521
|
-
}));
|
|
11522
|
-
}
|
|
11523
|
-
}),
|
|
11524
|
-
get_prev_node_usage: (0, import_back.tool)({
|
|
11525
|
-
description: "Returns historical CPU and memory usage for one or all nodes over the last N metrics readings.",
|
|
11526
|
-
inputSchema: import_back.z.object({
|
|
11527
|
-
nodeName: import_back.z.string().optional().describe("Node name to filter (omit for all nodes)"),
|
|
11528
|
-
count: import_back.z.number().optional().describe("Number of historical readings (default: 5)")
|
|
11529
|
-
}),
|
|
11530
|
-
execute: async ({ nodeName, count = 5 }) => {
|
|
11531
|
-
context.trace("get_prev_node_usage", { nodeName: nodeName ?? "*", count });
|
|
11532
|
-
if (context.clusterMetrics.length === 0) return { error: "No metrics available yet" };
|
|
11533
|
-
return context.clusterMetrics.slice(-count).map((reading) => ({
|
|
11534
|
-
nodes: (nodeName ? reading.nodes.filter((n) => n.name === nodeName) : reading.nodes).map((node) => ({
|
|
11535
|
-
name: node.name,
|
|
11536
|
-
cpuMillicores: Math.round((node.summary?.cpu?.usageNanoCores ?? 0) / 1e6),
|
|
11537
|
-
memoryMB: Math.round((node.summary?.memory?.workingSetBytes ?? 0) / 1024 / 1024),
|
|
11538
|
-
timestamp: node.timestamp
|
|
11539
|
-
}))
|
|
11540
|
-
}));
|
|
11541
|
-
}
|
|
11542
|
-
}),
|
|
11543
|
-
get_prev_deployment_usage: (0, import_back.tool)({
|
|
11544
|
-
description: "Returns historical aggregated CPU and memory usage for a deployment over the last N metrics readings.",
|
|
11545
|
-
inputSchema: import_back.z.object({
|
|
11546
|
-
namespace: import_back.z.string().describe("Namespace of the deployment"),
|
|
11547
|
-
name: import_back.z.string().describe("Name of the deployment"),
|
|
11548
|
-
count: import_back.z.number().optional().describe("Number of historical readings (default: 5)")
|
|
11549
|
-
}),
|
|
11550
|
-
execute: async ({ namespace, name, count = 5 }) => {
|
|
11551
|
-
context.trace("get_prev_deployment_usage", { namespace, name, count });
|
|
11552
|
-
try {
|
|
11553
|
-
if (context.clusterMetrics.length === 0) return { error: "No metrics available yet" };
|
|
11554
|
-
const deployResp = await context.clusterInfo.appsApi.readNamespacedDeployment({ name, namespace });
|
|
11555
|
-
const labelSelector = Object.entries(deployResp.spec?.selector?.matchLabels ?? {}).map(([k, v]) => `${k}=${v}`).join(",");
|
|
11556
|
-
const podsResp = await context.clusterInfo.coreApi.listNamespacedPod({ namespace, labelSelector });
|
|
11557
|
-
const podNames = new Set(podsResp.items.map((p) => p.metadata?.name));
|
|
11558
|
-
return context.clusterMetrics.slice(-count).map((reading) => {
|
|
11559
|
-
let totalCpuNanoCores = 0;
|
|
11560
|
-
let totalMemoryBytes = 0;
|
|
11561
|
-
let podCount = 0;
|
|
11562
|
-
for (const node of reading.nodes) {
|
|
11563
|
-
for (const pod of node.summary?.pods ?? []) {
|
|
11564
|
-
if (pod.podRef?.namespace === namespace && podNames.has(pod.podRef?.name)) {
|
|
11565
|
-
totalCpuNanoCores += pod.cpu?.usageNanoCores ?? 0;
|
|
11566
|
-
totalMemoryBytes += pod.memory?.workingSetBytes ?? 0;
|
|
11567
|
-
podCount++;
|
|
11568
|
-
}
|
|
11569
|
-
}
|
|
11570
|
-
}
|
|
11571
|
-
return {
|
|
11572
|
-
deployment: name,
|
|
11573
|
-
namespace,
|
|
11574
|
-
podCount,
|
|
11575
|
-
cpuMillicores: Math.round(totalCpuNanoCores / 1e6),
|
|
11576
|
-
memoryMB: Math.round(totalMemoryBytes / 1024 / 1024),
|
|
11577
|
-
timestamp: reading.nodes[0]?.timestamp
|
|
11578
|
-
};
|
|
11579
|
-
});
|
|
11580
|
-
} catch (err) {
|
|
11581
|
-
return { error: err.message ?? String(err) };
|
|
11582
|
-
}
|
|
11583
|
-
}
|
|
11584
|
-
}),
|
|
11585
|
-
get_prev_space_data: (0, import_back.tool)({
|
|
11586
|
-
description: "Returns historical aggregated CPU and memory usage for all pods in a namespace over the last N metrics readings.",
|
|
11587
|
-
inputSchema: import_back.z.object({
|
|
11588
|
-
namespace: import_back.z.string().describe("Namespace name"),
|
|
11589
|
-
count: import_back.z.number().optional().describe("Number of historical readings (default: 5)")
|
|
11590
|
-
}),
|
|
11591
|
-
execute: async ({ namespace, count = 5 }) => {
|
|
11592
|
-
context.trace("get_prev_space_data", { namespace, count });
|
|
11593
|
-
if (context.clusterMetrics.length === 0) return { error: "No metrics available yet" };
|
|
11594
|
-
return context.clusterMetrics.slice(-count).map((reading) => {
|
|
11595
|
-
let totalCpuNanoCores = 0;
|
|
11596
|
-
let totalMemoryBytes = 0;
|
|
11597
|
-
let podCount = 0;
|
|
11598
|
-
for (const node of reading.nodes) {
|
|
11599
|
-
for (const pod of node.summary?.pods ?? []) {
|
|
11600
|
-
if (pod.podRef?.namespace === namespace) {
|
|
11601
|
-
totalCpuNanoCores += pod.cpu?.usageNanoCores ?? 0;
|
|
11602
|
-
totalMemoryBytes += pod.memory?.workingSetBytes ?? 0;
|
|
11603
|
-
podCount++;
|
|
11604
|
-
}
|
|
11605
|
-
}
|
|
11606
|
-
}
|
|
11607
|
-
return {
|
|
11608
|
-
namespace,
|
|
11609
|
-
podCount,
|
|
11610
|
-
cpuMillicores: Math.round(totalCpuNanoCores / 1e6),
|
|
11611
|
-
memoryMB: Math.round(totalMemoryBytes / 1024 / 1024),
|
|
11612
|
-
timestamp: reading.nodes[0]?.timestamp
|
|
11613
|
-
};
|
|
11614
|
-
});
|
|
11615
|
-
}
|
|
11616
|
-
}),
|
|
11617
|
-
// ── CLUSTER ACTIONS ──────────────────────────────────────────────────
|
|
11618
|
-
add_node: (0, import_back.tool)({
|
|
11619
|
-
description: "Adds a new agent node to the cluster. For k3d uses `k3d node create <suffix> --cluster <name> --role agent`. For cloud providers (AKS/EKS/GKE) not yet implemented.",
|
|
11620
|
-
inputSchema: import_back.z.object({
|
|
11621
|
-
nodeName: import_back.z.string().optional().describe("Suffix for the new node name. For k3d the Kubernetes node will be named k3d-<cluster>-<nodeName>-0. Auto-generated if omitted."),
|
|
11622
|
-
nodePoolName: import_back.z.string().optional().describe("Node pool name (cloud provider specific, ignored for k3d)")
|
|
11623
|
-
}),
|
|
11624
|
-
execute: async ({ nodeName, nodePoolName }) => {
|
|
11625
|
-
context.trace("add_node", { nodeName: nodeName ?? "auto", nodePoolName: nodePoolName ?? "default" });
|
|
11626
|
-
if (context.clusterInfo.flavour === "k3d") {
|
|
11627
|
-
const suffix = nodeName ?? `agent-${Date.now()}`;
|
|
11628
|
-
const clusterName = context.clusterInfo.name.replace(/^k3d-/, "");
|
|
11629
|
-
try {
|
|
11630
|
-
const { stdout, stderr } = await execAsync(`k3d node create ${suffix} --cluster ${clusterName} --role agent`, { timeout: 12e4 });
|
|
11631
|
-
return { success: true, message: `New agent node '${suffix}' added to cluster '${clusterName}'`, stdout, stderr };
|
|
11632
|
-
} catch (err) {
|
|
11633
|
-
return { success: false, error: err.message ?? String(err) };
|
|
11634
|
-
}
|
|
11635
|
-
}
|
|
11636
|
-
return { success: false, message: `add_node not yet implemented for flavour '${context.clusterInfo.flavour}'` };
|
|
11637
|
-
}
|
|
11638
|
-
}),
|
|
11639
|
-
remove_node: (0, import_back.tool)({
|
|
11640
|
-
description: "Removes a node from the cluster. Cordons it first, then deletes it. For k3d uses `k3d node delete`. For cloud providers (AKS/EKS/GKE) not yet implemented.",
|
|
11641
|
-
inputSchema: import_back.z.object({
|
|
11642
|
-
nodeName: import_back.z.string().describe("Name of the Kubernetes node to remove (e.g. k3d-mycluster-agent-0)"),
|
|
11643
|
-
nodePoolName: import_back.z.string().optional().describe("Node pool name (cloud provider specific, ignored for k3d)")
|
|
11644
|
-
}),
|
|
11645
|
-
execute: async ({ nodeName, nodePoolName }) => {
|
|
11646
|
-
context.trace("remove_node", { nodeName, nodePoolName: nodePoolName ?? "default" });
|
|
11647
|
-
try {
|
|
11648
|
-
await context.clusterInfo.coreApi.patchNode({ name: nodeName, body: [{ op: "add", path: "/spec/unschedulable", value: true }] });
|
|
11649
|
-
} catch (_2) {
|
|
11650
|
-
}
|
|
11651
|
-
if (context.clusterInfo.flavour === "k3d") {
|
|
11652
|
-
try {
|
|
11653
|
-
const { stdout, stderr } = await execAsync(`k3d node delete ${nodeName}`, { timeout: 6e4 });
|
|
11654
|
-
return { success: true, message: `Node '${nodeName}' removed from cluster`, stdout, stderr };
|
|
11655
|
-
} catch (err) {
|
|
11656
|
-
return { success: false, error: err.message ?? String(err) };
|
|
11657
|
-
}
|
|
11658
|
-
}
|
|
11659
|
-
return { success: false, message: `remove_node not yet implemented for flavour '${context.clusterInfo.flavour}'` };
|
|
11660
|
-
}
|
|
11661
|
-
}),
|
|
11662
|
-
stop_node: (0, import_back.tool)({
|
|
11663
|
-
description: "Stops a running cluster node: cordons it in Kubernetes (marks it unschedulable) then stops the underlying container. For k3d uses `k3d node stop`. For other flavours only the cordon is applied.",
|
|
11664
|
-
inputSchema: import_back.z.object({
|
|
11665
|
-
nodeName: import_back.z.string().describe("Name of the Kubernetes node to stop (e.g. k3d-mycluster-agent-0)")
|
|
11666
|
-
}),
|
|
11667
|
-
execute: async ({ nodeName }) => {
|
|
11668
|
-
context.trace("stop_node", { nodeName });
|
|
11669
|
-
try {
|
|
11670
|
-
await context.clusterInfo.coreApi.patchNode({ name: nodeName, body: [{ op: "add", path: "/spec/unschedulable", value: true }] });
|
|
11671
|
-
} catch (err) {
|
|
11672
|
-
return { success: false, error: `Failed to cordon node: ${err.message ?? String(err)}` };
|
|
11673
|
-
}
|
|
11674
|
-
if (context.clusterInfo.flavour !== "k3d") {
|
|
11675
|
-
return { success: false, message: `Node '${nodeName}' cordoned but container stop is only implemented for k3d (flavour is '${context.clusterInfo.flavour}')` };
|
|
11676
|
-
}
|
|
11677
|
-
try {
|
|
11678
|
-
const { stdout, stderr } = await execAsync(`k3d node stop ${nodeName}`, { timeout: 3e4 });
|
|
11679
|
-
return { success: true, message: `Node '${nodeName}' cordoned and stopped`, stdout, stderr };
|
|
11680
|
-
} catch (err) {
|
|
11681
|
-
return { success: false, error: `Node cordoned but container stop failed: ${err.message ?? String(err)}` };
|
|
11682
|
-
}
|
|
11683
|
-
}
|
|
11684
|
-
}),
|
|
11685
|
-
start_node: (0, import_back.tool)({
|
|
11686
|
-
description: "Starts a previously stopped cluster node and uncordons it. For k3d uses `k3d node start`. For other flavours only the uncordon is applied.",
|
|
11687
|
-
inputSchema: import_back.z.object({
|
|
11688
|
-
nodeName: import_back.z.string().describe("Name of the Kubernetes node to start (e.g. k3d-mycluster-agent-0)")
|
|
11689
|
-
}),
|
|
11690
|
-
execute: async ({ nodeName }) => {
|
|
11691
|
-
context.trace("start_node", { nodeName });
|
|
11692
|
-
if (context.clusterInfo.flavour === "k3d") {
|
|
11693
|
-
try {
|
|
11694
|
-
const { stdout, stderr } = await execAsync(`k3d node start ${nodeName}`, { timeout: 3e4 });
|
|
11695
|
-
try {
|
|
11696
|
-
await context.clusterInfo.coreApi.patchNode({ name: nodeName, body: [{ op: "add", path: "/spec/unschedulable", value: false }] });
|
|
11697
|
-
} catch (_2) {
|
|
11698
|
-
}
|
|
11699
|
-
return { success: true, message: `Node '${nodeName}' started and uncordoned`, stdout, stderr };
|
|
11700
|
-
} catch (err) {
|
|
11701
|
-
return { success: false, error: err.message ?? String(err) };
|
|
11702
|
-
}
|
|
11703
|
-
}
|
|
11704
|
-
try {
|
|
11705
|
-
await context.clusterInfo.coreApi.patchNode({ name: nodeName, body: [{ op: "add", path: "/spec/unschedulable", value: false }] });
|
|
11706
|
-
return { success: false, message: `Node '${nodeName}' uncordoned but container start is only implemented for k3d (flavour is '${context.clusterInfo.flavour}')` };
|
|
11707
|
-
} catch (err) {
|
|
11708
|
-
return { success: false, error: `Container start not implemented for this flavour and uncordon failed: ${err.message ?? String(err)}` };
|
|
11709
|
-
}
|
|
11710
|
-
}
|
|
11711
|
-
}),
|
|
11712
|
-
add_replica: (0, import_back.tool)({
|
|
11713
|
-
description: "Scales up a deployment by adding one replica.",
|
|
11714
|
-
inputSchema: import_back.z.object({
|
|
11715
|
-
namespace: import_back.z.string().describe("Namespace of the deployment"),
|
|
11716
|
-
name: import_back.z.string().describe("Name of the deployment")
|
|
11717
|
-
}),
|
|
11718
|
-
execute: async ({ namespace, name }) => {
|
|
11719
|
-
context.trace("add_replica", { namespace, name });
|
|
11720
|
-
try {
|
|
11721
|
-
const deployResp = await context.clusterInfo.appsApi.readNamespacedDeployment({ name, namespace });
|
|
11722
|
-
const currentReplicas = deployResp.spec?.replicas ?? 1;
|
|
11723
|
-
const newReplicas = currentReplicas + 1;
|
|
11724
|
-
const patch = [{ op: "replace", path: "/spec/replicas", value: newReplicas }];
|
|
11725
|
-
await context.clusterInfo.appsApi.patchNamespacedDeployment({ name, namespace, body: patch });
|
|
11726
|
-
return { success: true, message: `Deployment ${namespace}/${name} scaled from ${currentReplicas} to ${newReplicas} replicas` };
|
|
11727
|
-
} catch (err) {
|
|
11728
|
-
return { success: false, error: err.message ?? String(err) };
|
|
11729
|
-
}
|
|
11730
|
-
}
|
|
11731
|
-
}),
|
|
11732
|
-
remove_replica: (0, import_back.tool)({
|
|
11733
|
-
description: "Scales down a deployment by removing one replica. Minimum of 1 replica is enforced.",
|
|
11734
|
-
inputSchema: import_back.z.object({
|
|
11735
|
-
namespace: import_back.z.string().describe("Namespace of the deployment"),
|
|
11736
|
-
name: import_back.z.string().describe("Name of the deployment")
|
|
11737
|
-
}),
|
|
11738
|
-
execute: async ({ namespace, name }) => {
|
|
11739
|
-
context.trace("remove_replica", { namespace, name });
|
|
11740
|
-
try {
|
|
11741
|
-
const deployResp = await context.clusterInfo.appsApi.readNamespacedDeployment({ name, namespace });
|
|
11742
|
-
const currentReplicas = deployResp.spec?.replicas ?? 1;
|
|
11743
|
-
if (currentReplicas <= 1) return { success: false, message: `Deployment ${namespace}/${name} already at minimum (${currentReplicas} replica)` };
|
|
11744
|
-
const newReplicas = currentReplicas - 1;
|
|
11745
|
-
const patch = [{ op: "replace", path: "/spec/replicas", value: newReplicas }];
|
|
11746
|
-
await context.clusterInfo.appsApi.patchNamespacedDeployment({ name, namespace, body: patch });
|
|
11747
|
-
return { success: true, message: `Deployment ${namespace}/${name} scaled from ${currentReplicas} to ${newReplicas} replicas` };
|
|
11748
|
-
} catch (err) {
|
|
11749
|
-
return { success: false, error: err.message ?? String(err) };
|
|
11750
|
-
}
|
|
11751
|
-
}
|
|
11752
|
-
}),
|
|
11753
|
-
// ── MISC ─────────────────────────────────────────────────────────────
|
|
11754
|
-
times_two: (0, import_back.tool)({
|
|
11755
|
-
description: "Multiplies a number by two",
|
|
11756
|
-
inputSchema: import_back.z.object({
|
|
11757
|
-
data: import_back.z.number()
|
|
11758
|
-
}),
|
|
11759
|
-
execute: async ({ data }) => {
|
|
11760
|
-
context.trace("times_two", { data });
|
|
11761
|
-
return data * 2;
|
|
11762
|
-
}
|
|
11763
|
-
}),
|
|
11764
|
-
father_of: (0, import_back.tool)({
|
|
11765
|
-
description: "Returns the name of the father of a person",
|
|
11766
|
-
inputSchema: import_back.z.object({
|
|
11767
|
-
data: import_back.z.string().describe("The name of the person whose father you want to discover")
|
|
11768
|
-
}),
|
|
11769
|
-
execute: async ({ data }) => {
|
|
11770
|
-
context.trace("father_of", { data });
|
|
11771
|
-
return "Julio";
|
|
11772
|
-
}
|
|
11773
|
-
})
|
|
11774
|
-
};
|
|
11775
|
-
};
|
|
11776
|
-
var getToolByName = (name, context) => {
|
|
11777
|
-
const tools = createTools(context);
|
|
11778
|
-
return tools[name];
|
|
11779
|
-
};
|
|
11780
|
-
var toolInfoList = [
|
|
11781
|
-
{ name: "get_node_data", description: "Returns configuration info about all Kubernetes nodes (name, IP). Configuration only \u2014 not workload or usage data." },
|
|
11782
|
-
{ name: "get_cluster_data", description: "Returns general cluster info: name, flavour (AKS/EKS/GKE/k3s/k3d), total vCPUs, total memory, node count and readiness status." },
|
|
11783
|
-
{ name: "get_workload_data", description: "Returns all workloads in the cluster: deployments, statefulsets, daemonsets, pods and services. Optionally filter by namespace." },
|
|
11784
|
-
{ name: "get_space_data", description: "Returns all resources in a specific Kubernetes namespace: pods (with restart count), deployments, services, configmap names." },
|
|
11785
|
-
{ name: "get_cluster_usage", description: "Returns current overall cluster resource usage: CPU%, memory%, network Mbps, total vCPUs and total memory GB." },
|
|
11786
|
-
{ name: "get_node_usage", description: "Returns current CPU and memory usage for one node or all nodes from the latest metrics reading." },
|
|
11787
|
-
{ name: "get_deployment_usage", description: "Returns current aggregated CPU and memory usage for all pods belonging to a specific deployment." },
|
|
11788
|
-
{ name: "get_prev_cluster_usage", description: "Returns historical overall cluster usage over the last N metrics readings (CPU%, memory%, network Mbps)." },
|
|
11789
|
-
{ name: "get_prev_node_usage", description: "Returns historical CPU and memory usage for one or all nodes over the last N metrics readings." },
|
|
11790
|
-
{ name: "get_prev_deployment_usage", description: "Returns historical aggregated CPU and memory usage for a deployment over the last N metrics readings." },
|
|
11791
|
-
{ name: "get_prev_space_data", description: "Returns historical aggregated CPU and memory usage for all pods in a namespace over the last N metrics readings." },
|
|
11792
|
-
{ name: "add_node", description: "Adds a new agent node to the cluster. For k3d uses `k3d node create`. Cloud providers not yet implemented." },
|
|
11793
|
-
{ name: "remove_node", description: "Removes a node from the cluster (cordon + delete). For k3d uses `k3d node delete`. Cloud providers not yet implemented." },
|
|
11794
|
-
{ name: "stop_node", description: "Stops a running node: cordons it and stops the container. For k3d uses `k3d node stop`." },
|
|
11795
|
-
{ name: "start_node", description: "Starts a stopped node and uncordons it. For k3d uses `k3d node start`." },
|
|
11796
|
-
{ name: "add_replica", description: "Scales up a deployment by adding one replica." },
|
|
11797
|
-
{ name: "remove_replica", description: "Scales down a deployment by removing one replica. Minimum of 1 replica is enforced." },
|
|
11798
|
-
{ name: "times_two", description: "Multiplies a number by two." },
|
|
11799
|
-
{ name: "father_of", description: "Returns the name of the father of a person." }
|
|
11800
|
-
];
|
|
11801
|
-
|
|
11802
|
-
// src/back/index.ts
|
|
11266
|
+
var import_back2 = __toESM(require_back(), 1);
|
|
11803
11267
|
var _ = require_lodash();
|
|
11804
11268
|
var nunjucks = require_nunjucks();
|
|
11805
11269
|
nunjucks.configure({ autoescape: true });
|
|
@@ -11818,8 +11282,12 @@ var PinocchioChannel = class {
|
|
|
11818
11282
|
triggers: [],
|
|
11819
11283
|
llms: []
|
|
11820
11284
|
};
|
|
11285
|
+
this.startChannelReady = null;
|
|
11821
11286
|
this.playgroundTrigger = void 0;
|
|
11822
|
-
this.startChannel =
|
|
11287
|
+
this.startChannel = () => {
|
|
11288
|
+
this.startChannelReady = this._startChannelImpl();
|
|
11289
|
+
};
|
|
11290
|
+
this._startChannelImpl = async () => {
|
|
11823
11291
|
this.clusterInfo.addSubscriber("metrics", this, {});
|
|
11824
11292
|
this.clusterInfo.addSubscriber("business", this, {
|
|
11825
11293
|
spaces: [
|
|
@@ -11835,14 +11303,23 @@ var PinocchioChannel = class {
|
|
|
11835
11303
|
});
|
|
11836
11304
|
let provs = await this.backChannelObject.readStorageCommon(import_kwirth_common_ai.STORAGE_KEY_PROVIDERS, true);
|
|
11837
11305
|
if (provs) this.providers = provs;
|
|
11838
|
-
let
|
|
11306
|
+
let rawConfig = await this.backChannelObject.readStorage("pinocchio-config", false);
|
|
11307
|
+
let config = null;
|
|
11308
|
+
if (typeof rawConfig === "string") {
|
|
11309
|
+
try {
|
|
11310
|
+
config = JSON.parse(rawConfig);
|
|
11311
|
+
} catch {
|
|
11312
|
+
}
|
|
11313
|
+
} else if (rawConfig) {
|
|
11314
|
+
config = rawConfig;
|
|
11315
|
+
}
|
|
11839
11316
|
if (config) this.pinocchioConfig = config;
|
|
11840
11317
|
try {
|
|
11841
11318
|
const sharedLlms = await this.backChannelObject.readStorageCommon(import_kwirth_common_ai.STORAGE_KEY_LLMS, false);
|
|
11842
11319
|
if (sharedLlms?.length) this.pinocchioConfig.llms = sharedLlms;
|
|
11843
11320
|
} catch {
|
|
11844
11321
|
}
|
|
11845
|
-
(0,
|
|
11322
|
+
(0, import_back.loadModels)(this.providers, this.backChannelObject);
|
|
11846
11323
|
};
|
|
11847
11324
|
this.getChannelData = () => {
|
|
11848
11325
|
return {
|
|
@@ -11869,7 +11346,7 @@ var PinocchioChannel = class {
|
|
|
11869
11346
|
this.broadcastError(`Cannot find LLM with id '${version.llm}'`);
|
|
11870
11347
|
return void 0;
|
|
11871
11348
|
}
|
|
11872
|
-
const model = (0,
|
|
11349
|
+
const model = (0, import_back.buildModel)(llm, this.providers);
|
|
11873
11350
|
if (!model) {
|
|
11874
11351
|
this.broadcastError(`Cannot build model for LLM '${version.llm}' (provider: ${llm.provider})`);
|
|
11875
11352
|
return void 0;
|
|
@@ -11910,17 +11387,15 @@ var PinocchioChannel = class {
|
|
|
11910
11387
|
let temperature = llm.temperature;
|
|
11911
11388
|
if (temperature < 0) temperature = 0;
|
|
11912
11389
|
if (temperature > 1) temperature = 1;
|
|
11913
|
-
|
|
11390
|
+
const toolContext = {
|
|
11914
11391
|
origin: "Pinocchio",
|
|
11915
11392
|
nodes: await this.clusterInfo.getNodes(),
|
|
11916
11393
|
clusterInfo: this.clusterInfo,
|
|
11917
11394
|
clusterMetrics: this.clusterMetrics,
|
|
11918
11395
|
trace: (toolName, args) => this.backChannelObject.logTrace?.(`[pinocchio] tool ${toolName} ${JSON.stringify(args)}`)
|
|
11919
11396
|
};
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
tools[toolName] = getToolByName(toolName, context);
|
|
11923
|
-
}
|
|
11397
|
+
const toolNames = version.autoTools ? import_back.toolInfoList.map((t) => t.name) : version.tools ?? [];
|
|
11398
|
+
const tools = Object.fromEntries(toolNames.filter((n) => n in import_back.tools).map((n) => [n, import_back.tools[n]]));
|
|
11924
11399
|
let providerOptions = {};
|
|
11925
11400
|
let errorPath = "";
|
|
11926
11401
|
switch (llm.provider) {
|
|
@@ -11945,6 +11420,7 @@ var PinocchioChannel = class {
|
|
|
11945
11420
|
errorPath,
|
|
11946
11421
|
temperature,
|
|
11947
11422
|
tools,
|
|
11423
|
+
toolContext,
|
|
11948
11424
|
prompt,
|
|
11949
11425
|
system
|
|
11950
11426
|
};
|
|
@@ -11987,7 +11463,7 @@ var PinocchioChannel = class {
|
|
|
11987
11463
|
flow: import_kwirth_common.EInstanceMessageFlow.RESPONSE,
|
|
11988
11464
|
type: import_kwirth_common.EInstanceMessageType.DATA,
|
|
11989
11465
|
instance: instance.instanceId,
|
|
11990
|
-
toolsAvailable: toolInfoList
|
|
11466
|
+
toolsAvailable: import_back.toolInfoList
|
|
11991
11467
|
};
|
|
11992
11468
|
webSocket.send(JSON.stringify(msgToolsAvailable));
|
|
11993
11469
|
break;
|
|
@@ -12009,7 +11485,7 @@ var PinocchioChannel = class {
|
|
|
12009
11485
|
let provs = pinocchioMessage.data;
|
|
12010
11486
|
this.providers = provs;
|
|
12011
11487
|
await this.backChannelObject.writeStorageCommon(import_kwirth_common_ai.STORAGE_KEY_PROVIDERS, true, provs);
|
|
12012
|
-
await (0,
|
|
11488
|
+
await (0, import_back.loadModels)(this.providers, this.backChannelObject);
|
|
12013
11489
|
this.executeProvidersGet();
|
|
12014
11490
|
this.sendSignalMessage(webSocket, import_kwirth_common.EInstanceMessageAction.COMMAND, import_kwirth_common.EInstanceMessageFlow.RESPONSE, import_kwirth_common.ESignalMessageLevel.INFO, instance.instanceId, "Providers updated");
|
|
12015
11491
|
break;
|
|
@@ -12049,7 +11525,7 @@ var PinocchioChannel = class {
|
|
|
12049
11525
|
try {
|
|
12050
11526
|
const invocation = await this.buildModelInvocation(dummyTrigger, version, fakeEvent);
|
|
12051
11527
|
if (!invocation) return;
|
|
12052
|
-
const { model, temperature, providerOptions, tools, prompt: effectivePrompt } = invocation;
|
|
11528
|
+
const { model, temperature, providerOptions, tools, toolContext, prompt: effectivePrompt } = invocation;
|
|
12053
11529
|
this.broadcastPlaygroundMessage(`[Playground] type: ${triggerType}`);
|
|
12054
11530
|
this.broadcastPlaygroundMessage(`[Playground] llm: ${version.llm}`);
|
|
12055
11531
|
this.broadcastPlaygroundMessage(`[Playground] system: ${version.system || "(none)"}`);
|
|
@@ -12058,7 +11534,7 @@ var PinocchioChannel = class {
|
|
|
12058
11534
|
let activeTools = tools;
|
|
12059
11535
|
if (version.autoTools && Object.keys(tools).length > 0) {
|
|
12060
11536
|
const toolListStr = Object.keys(tools).join(", ");
|
|
12061
|
-
const { text: selectionText } = await (0,
|
|
11537
|
+
const { text: selectionText } = await (0, import_back2.generateText)({
|
|
12062
11538
|
model,
|
|
12063
11539
|
temperature,
|
|
12064
11540
|
providerOptions,
|
|
@@ -12071,15 +11547,15 @@ Available tools: ${toolListStr}`
|
|
|
12071
11547
|
this.broadcastPlaygroundMessage(`[Auto tools] selected: ${selectedNames.join(", ") || "(none)"}`);
|
|
12072
11548
|
activeTools = Object.fromEntries(selectedNames.map((n) => [n, tools[n]]));
|
|
12073
11549
|
}
|
|
12074
|
-
const { text: phase1Text, usage: usage1, steps } = await (0,
|
|
11550
|
+
const { text: phase1Text, usage: usage1, steps } = await (0, import_back.runWithToolContext)(toolContext, () => (0, import_back2.generateText)({
|
|
12075
11551
|
model,
|
|
12076
11552
|
temperature,
|
|
12077
|
-
stopWhen: (0,
|
|
11553
|
+
stopWhen: (0, import_back2.stepCountIs)(version.steps || 5),
|
|
12078
11554
|
tools: activeTools,
|
|
12079
11555
|
providerOptions,
|
|
12080
11556
|
system: version.system || "You are a helpful assistant.",
|
|
12081
11557
|
prompt: effectivePrompt
|
|
12082
|
-
});
|
|
11558
|
+
}));
|
|
12083
11559
|
const toolLines = [];
|
|
12084
11560
|
for (const step of steps) {
|
|
12085
11561
|
const s = step;
|
|
@@ -12103,7 +11579,7 @@ Information gathered from tools:
|
|
|
12103
11579
|
${toolLines.join("\n")}
|
|
12104
11580
|
|
|
12105
11581
|
Please provide a comprehensive answer based on the above data.`;
|
|
12106
|
-
const { text: phase2Text, usage: usage2 } = await (0,
|
|
11582
|
+
const { text: phase2Text, usage: usage2 } = await (0, import_back2.generateText)({
|
|
12107
11583
|
model,
|
|
12108
11584
|
temperature,
|
|
12109
11585
|
providerOptions,
|
|
@@ -12213,6 +11689,7 @@ Please provide a comprehensive answer based on the above data.`;
|
|
|
12213
11689
|
// PRIVATE
|
|
12214
11690
|
// *************************************************************************************
|
|
12215
11691
|
this.executeConfigGet = async () => {
|
|
11692
|
+
if (this.startChannelReady) await this.startChannelReady;
|
|
12216
11693
|
try {
|
|
12217
11694
|
const sharedLlms = await this.backChannelObject.readStorageCommon(import_kwirth_common_ai.STORAGE_KEY_LLMS, false);
|
|
12218
11695
|
if (sharedLlms?.length) this.pinocchioConfig.llms = sharedLlms;
|
|
@@ -12239,7 +11716,7 @@ Please provide a comprehensive answer based on the above data.`;
|
|
|
12239
11716
|
const freshProviders = await this.backChannelObject.readStorageCommon(import_kwirth_common_ai.STORAGE_KEY_PROVIDERS, true);
|
|
12240
11717
|
if (freshProviders?.length) {
|
|
12241
11718
|
this.providers = freshProviders;
|
|
12242
|
-
await (0,
|
|
11719
|
+
await (0, import_back.loadModels)(this.providers, this.backChannelObject);
|
|
12243
11720
|
}
|
|
12244
11721
|
} catch {
|
|
12245
11722
|
}
|
|
@@ -12373,23 +11850,23 @@ Please provide a comprehensive answer based on the above data.`;
|
|
|
12373
11850
|
for (let t of this.pinocchioConfig.triggers.filter((t2) => t2.trigger === "business")) {
|
|
12374
11851
|
for (let version of t.versions.filter((v) => v.enabled)) {
|
|
12375
11852
|
try {
|
|
12376
|
-
let { llmModelId, llmProviderId, model, temperature, providerOptions, errorPath, system, prompt, tools } = await this.buildModelInvocation(t, version, businessEvent) || {};
|
|
11853
|
+
let { llmModelId, llmProviderId, model, temperature, providerOptions, errorPath, system, prompt, tools, toolContext } = await this.buildModelInvocation(t, version, businessEvent) || {};
|
|
12377
11854
|
if (!model) return;
|
|
12378
11855
|
this.broadcastMessage(`Received business event ${JSON.stringify(businessEvent.last.event)}`);
|
|
12379
|
-
const { output, usage, steps } = await (0,
|
|
11856
|
+
const { output, usage, steps } = await (0, import_back.runWithToolContext)(toolContext, () => (0, import_back2.generateText)({
|
|
12380
11857
|
model,
|
|
12381
11858
|
temperature,
|
|
12382
|
-
stopWhen: (0,
|
|
11859
|
+
stopWhen: (0, import_back2.stepCountIs)(15),
|
|
12383
11860
|
tools,
|
|
12384
11861
|
providerOptions,
|
|
12385
|
-
output:
|
|
12386
|
-
schema:
|
|
12387
|
-
response:
|
|
11862
|
+
output: import_back2.Output.object({
|
|
11863
|
+
schema: import_back2.z.object({
|
|
11864
|
+
response: import_back2.z.string().describe("response to the question")
|
|
12388
11865
|
})
|
|
12389
11866
|
}),
|
|
12390
11867
|
system: "Use the tools provided to find information, and once you have the data, format your final response strictly as a JSON object according to the schema.",
|
|
12391
11868
|
prompt: prompt || "Hi AI, how are you?"
|
|
12392
|
-
});
|
|
11869
|
+
}));
|
|
12393
11870
|
this.broadcastMessage(JSON.stringify(output.response));
|
|
12394
11871
|
} catch (err) {
|
|
12395
11872
|
let message = `Pinocchio analysis ended in error when processing 'business' while analyzing`;
|
|
@@ -12419,29 +11896,29 @@ Please provide a comprehensive answer based on the above data.`;
|
|
|
12419
11896
|
continue;
|
|
12420
11897
|
}
|
|
12421
11898
|
}
|
|
12422
|
-
let { llmModelId, llmProviderId, model, temperature, providerOptions, errorPath, system, prompt, tools } = await this.buildModelInvocation(t, version, eventsEvent) || {};
|
|
11899
|
+
let { llmModelId, llmProviderId, model, temperature, providerOptions, errorPath, system, prompt, tools, toolContext } = await this.buildModelInvocation(t, version, eventsEvent) || {};
|
|
12423
11900
|
if (!model) return;
|
|
12424
11901
|
try {
|
|
12425
|
-
const { output, usage } = await (0,
|
|
11902
|
+
const { output, usage } = await (0, import_back.runWithToolContext)(toolContext, () => (0, import_back2.generateText)({
|
|
12426
11903
|
model,
|
|
12427
11904
|
temperature,
|
|
12428
11905
|
tools,
|
|
12429
11906
|
providerOptions,
|
|
12430
|
-
output:
|
|
12431
|
-
schema:
|
|
12432
|
-
findings:
|
|
12433
|
-
|
|
12434
|
-
description:
|
|
12435
|
-
level:
|
|
11907
|
+
output: import_back2.Output.object({
|
|
11908
|
+
schema: import_back2.z.object({
|
|
11909
|
+
findings: import_back2.z.array(
|
|
11910
|
+
import_back2.z.object({
|
|
11911
|
+
description: import_back2.z.string().min(1),
|
|
11912
|
+
level: import_back2.z.enum(["low", "medium", "high", "critical"])
|
|
12436
11913
|
})
|
|
12437
11914
|
),
|
|
12438
|
-
report:
|
|
12439
|
-
hardened_yaml:
|
|
11915
|
+
report: import_back2.z.string().min(1),
|
|
11916
|
+
hardened_yaml: import_back2.z.string().min(1)
|
|
12440
11917
|
})
|
|
12441
11918
|
}),
|
|
12442
11919
|
system: system || "You are a very polite AI system",
|
|
12443
11920
|
prompt: prompt || "Hi AI, how are you?"
|
|
12444
|
-
});
|
|
11921
|
+
}));
|
|
12445
11922
|
let analysis = {
|
|
12446
11923
|
text: `${eventsEvent.type} ${eventsEvent.obj.kind} '${eventsEvent.obj.metadata.name}' in namespace '${eventsEvent.obj.metadata.namespace}' [LLM:${llmProviderId}/${llmModelId}, IN:${usage.inputTokens}, OUT:${usage.outputTokens}]`,
|
|
12447
11924
|
findings: output.findings,
|