mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-09 06:50:46 +08:00
Fix bizMonitor tool results failing DSH lossless JSON (strip undefined holes).
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
b235957c34
commit
4dd628b7cc
13 changed files with 414 additions and 136 deletions
|
|
@ -737,6 +737,32 @@ function watchKbContext(listener) {
|
|||
};
|
||||
}
|
||||
|
||||
// src/netx/json-safe.ts
|
||||
function toLosslessJson(value) {
|
||||
try {
|
||||
const text = JSON.stringify(value);
|
||||
if (text === undefined) {
|
||||
return { ok: false, error: "tool_result_not_json", detail: "undefined_root" };
|
||||
}
|
||||
const parsed = JSON.parse(text);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return { ok: true, data: { value: parsed } };
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
return { ok: false, error: "tool_result_not_json", detail: detail.slice(0, 400) };
|
||||
}
|
||||
}
|
||||
function omitUndefined(record) {
|
||||
const out = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
if (value !== undefined)
|
||||
out[key] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// src/netx/kb-local-tools.ts
|
||||
var str = (description) => ({ type: "string", ...description ? { description } : {} });
|
||||
var bool = (description) => ({ type: "boolean", ...description ? { description } : {} });
|
||||
|
|
@ -766,7 +792,7 @@ function tool(name, description, parameters, execute) {
|
|||
isConcurrencySafe: () => false,
|
||||
async execute(args) {
|
||||
try {
|
||||
return await execute(args);
|
||||
return toLosslessJson(await execute(args));
|
||||
} catch (error) {
|
||||
throw new Error(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
|
|
@ -1481,7 +1507,7 @@ function taskBriefNe(brief) {
|
|||
}
|
||||
function slimMigrationProject(row) {
|
||||
const mt = asRecord(row.monitor_template);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
status: row.status,
|
||||
|
|
@ -1498,7 +1524,7 @@ function slimMigrationProject(row) {
|
|||
hf_start_at: row.hf_start_at,
|
||||
hf_end_at: row.hf_end_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function matchesBizMonitorQ(row, q) {
|
||||
if (!q)
|
||||
|
|
@ -1567,7 +1593,7 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks = tasks.slice(0, limit);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
projects: wantProjects ? projects : undefined,
|
||||
tasks: wantTasks ? tasks : undefined,
|
||||
|
|
@ -1578,11 +1604,11 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks_returned: wantTasks ? tasks.length : 0
|
||||
},
|
||||
next: "Pass project_id (or task_id) to netx__getBizMonitorContext; then listBizMonitorBatches for batch_id / run_id."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
function slimCutoverBatch(row) {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
project_id: row.project_id,
|
||||
batch_label: row.batch_label,
|
||||
|
|
@ -1594,12 +1620,12 @@ function slimCutoverBatch(row) {
|
|||
note: row.note,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimCollectBatch(row, taskId = "") {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
task_id: row.task_id || taskId,
|
||||
task_id: row.task_id || taskId || undefined,
|
||||
status: row.status,
|
||||
ne_name: row.ne_name,
|
||||
command_count: row.command_count,
|
||||
|
|
@ -1609,12 +1635,12 @@ function slimCollectBatch(row, taskId = "") {
|
|||
message: row.message,
|
||||
started_at: row.started_at,
|
||||
ended_at: row.ended_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimEvalRun(row) {
|
||||
const summary = asRecord(row.summary);
|
||||
const progress = asRecord(summary.progress);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
batch_id: row.batch_id,
|
||||
purpose: row.purpose,
|
||||
|
|
@ -1624,7 +1650,7 @@ function slimEvalRun(row) {
|
|||
anomaly: summary.anomaly,
|
||||
progress_ok: progress.ok ?? summary.progress_ok,
|
||||
progress_total: progress.total ?? summary.progress_total
|
||||
};
|
||||
});
|
||||
}
|
||||
async function listBizMonitorBatches(client, args, signal) {
|
||||
const projectId = str2(args, "project_id").trim();
|
||||
|
|
@ -1733,7 +1759,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
}
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
project_id: projectId || undefined,
|
||||
task_id: taskId || undefined,
|
||||
|
|
@ -1747,7 +1773,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
runs: runs.length
|
||||
},
|
||||
next: wantCutover ? "Use cutover batch id with netx__getBizMonitorBoard / listBizMonitorBatches(kind=runs). Collect batch id → netx__getBizCollectBatch." : wantCollect ? "Pass collect batch id to netx__getBizCollectBatch / getBizCollectCommandRaw." : "Pass run_id to netx__getBizMonitorDiffs or getBizMonitorBoard(run_id)."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
async function getBizMonitorContext(client, args, signal) {
|
||||
|
|
@ -2491,10 +2517,11 @@ function tool2(name, description, parameters, handler, getClient, timeoutMs) {
|
|||
isConcurrencySafe: () => true,
|
||||
async execute(args, exec) {
|
||||
const result = await handler(getClient(), args, exec.signal);
|
||||
if (result.ok === false) {
|
||||
throw new Error(JSON.stringify(result));
|
||||
const safe = toLosslessJson(result);
|
||||
if (result.ok === false || safe.ok === false) {
|
||||
throw new Error(JSON.stringify(safe));
|
||||
}
|
||||
return result;
|
||||
return safe;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -737,6 +737,32 @@ function watchKbContext(listener) {
|
|||
};
|
||||
}
|
||||
|
||||
// src/netx/json-safe.ts
|
||||
function toLosslessJson(value) {
|
||||
try {
|
||||
const text = JSON.stringify(value);
|
||||
if (text === undefined) {
|
||||
return { ok: false, error: "tool_result_not_json", detail: "undefined_root" };
|
||||
}
|
||||
const parsed = JSON.parse(text);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return { ok: true, data: { value: parsed } };
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
return { ok: false, error: "tool_result_not_json", detail: detail.slice(0, 400) };
|
||||
}
|
||||
}
|
||||
function omitUndefined(record) {
|
||||
const out = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
if (value !== undefined)
|
||||
out[key] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// src/netx/kb-local-tools.ts
|
||||
var str = (description) => ({ type: "string", ...description ? { description } : {} });
|
||||
var bool = (description) => ({ type: "boolean", ...description ? { description } : {} });
|
||||
|
|
@ -766,7 +792,7 @@ function tool(name, description, parameters, execute) {
|
|||
isConcurrencySafe: () => false,
|
||||
async execute(args) {
|
||||
try {
|
||||
return await execute(args);
|
||||
return toLosslessJson(await execute(args));
|
||||
} catch (error) {
|
||||
throw new Error(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
|
|
@ -1481,7 +1507,7 @@ function taskBriefNe(brief) {
|
|||
}
|
||||
function slimMigrationProject(row) {
|
||||
const mt = asRecord(row.monitor_template);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
status: row.status,
|
||||
|
|
@ -1498,7 +1524,7 @@ function slimMigrationProject(row) {
|
|||
hf_start_at: row.hf_start_at,
|
||||
hf_end_at: row.hf_end_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function matchesBizMonitorQ(row, q) {
|
||||
if (!q)
|
||||
|
|
@ -1567,7 +1593,7 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks = tasks.slice(0, limit);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
projects: wantProjects ? projects : undefined,
|
||||
tasks: wantTasks ? tasks : undefined,
|
||||
|
|
@ -1578,11 +1604,11 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks_returned: wantTasks ? tasks.length : 0
|
||||
},
|
||||
next: "Pass project_id (or task_id) to netx__getBizMonitorContext; then listBizMonitorBatches for batch_id / run_id."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
function slimCutoverBatch(row) {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
project_id: row.project_id,
|
||||
batch_label: row.batch_label,
|
||||
|
|
@ -1594,12 +1620,12 @@ function slimCutoverBatch(row) {
|
|||
note: row.note,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimCollectBatch(row, taskId = "") {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
task_id: row.task_id || taskId,
|
||||
task_id: row.task_id || taskId || undefined,
|
||||
status: row.status,
|
||||
ne_name: row.ne_name,
|
||||
command_count: row.command_count,
|
||||
|
|
@ -1609,12 +1635,12 @@ function slimCollectBatch(row, taskId = "") {
|
|||
message: row.message,
|
||||
started_at: row.started_at,
|
||||
ended_at: row.ended_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimEvalRun(row) {
|
||||
const summary = asRecord(row.summary);
|
||||
const progress = asRecord(summary.progress);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
batch_id: row.batch_id,
|
||||
purpose: row.purpose,
|
||||
|
|
@ -1624,7 +1650,7 @@ function slimEvalRun(row) {
|
|||
anomaly: summary.anomaly,
|
||||
progress_ok: progress.ok ?? summary.progress_ok,
|
||||
progress_total: progress.total ?? summary.progress_total
|
||||
};
|
||||
});
|
||||
}
|
||||
async function listBizMonitorBatches(client, args, signal) {
|
||||
const projectId = str2(args, "project_id").trim();
|
||||
|
|
@ -1733,7 +1759,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
}
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
project_id: projectId || undefined,
|
||||
task_id: taskId || undefined,
|
||||
|
|
@ -1747,7 +1773,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
runs: runs.length
|
||||
},
|
||||
next: wantCutover ? "Use cutover batch id with netx__getBizMonitorBoard / listBizMonitorBatches(kind=runs). Collect batch id → netx__getBizCollectBatch." : wantCollect ? "Pass collect batch id to netx__getBizCollectBatch / getBizCollectCommandRaw." : "Pass run_id to netx__getBizMonitorDiffs or getBizMonitorBoard(run_id)."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
async function getBizMonitorContext(client, args, signal) {
|
||||
|
|
@ -2491,10 +2517,11 @@ function tool2(name, description, parameters, handler, getClient, timeoutMs) {
|
|||
isConcurrencySafe: () => true,
|
||||
async execute(args, exec) {
|
||||
const result = await handler(getClient(), args, exec.signal);
|
||||
if (result.ok === false) {
|
||||
throw new Error(JSON.stringify(result));
|
||||
const safe = toLosslessJson(result);
|
||||
if (result.ok === false || safe.ok === false) {
|
||||
throw new Error(JSON.stringify(safe));
|
||||
}
|
||||
return result;
|
||||
return safe;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -737,6 +737,32 @@ function watchKbContext(listener) {
|
|||
};
|
||||
}
|
||||
|
||||
// src/netx/json-safe.ts
|
||||
function toLosslessJson(value) {
|
||||
try {
|
||||
const text = JSON.stringify(value);
|
||||
if (text === undefined) {
|
||||
return { ok: false, error: "tool_result_not_json", detail: "undefined_root" };
|
||||
}
|
||||
const parsed = JSON.parse(text);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return { ok: true, data: { value: parsed } };
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
return { ok: false, error: "tool_result_not_json", detail: detail.slice(0, 400) };
|
||||
}
|
||||
}
|
||||
function omitUndefined(record) {
|
||||
const out = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
if (value !== undefined)
|
||||
out[key] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// src/netx/kb-local-tools.ts
|
||||
var str = (description) => ({ type: "string", ...description ? { description } : {} });
|
||||
var bool = (description) => ({ type: "boolean", ...description ? { description } : {} });
|
||||
|
|
@ -766,7 +792,7 @@ function tool(name, description, parameters, execute) {
|
|||
isConcurrencySafe: () => false,
|
||||
async execute(args) {
|
||||
try {
|
||||
return await execute(args);
|
||||
return toLosslessJson(await execute(args));
|
||||
} catch (error) {
|
||||
throw new Error(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
|
|
@ -1481,7 +1507,7 @@ function taskBriefNe(brief) {
|
|||
}
|
||||
function slimMigrationProject(row) {
|
||||
const mt = asRecord(row.monitor_template);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
status: row.status,
|
||||
|
|
@ -1498,7 +1524,7 @@ function slimMigrationProject(row) {
|
|||
hf_start_at: row.hf_start_at,
|
||||
hf_end_at: row.hf_end_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function matchesBizMonitorQ(row, q) {
|
||||
if (!q)
|
||||
|
|
@ -1567,7 +1593,7 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks = tasks.slice(0, limit);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
projects: wantProjects ? projects : undefined,
|
||||
tasks: wantTasks ? tasks : undefined,
|
||||
|
|
@ -1578,11 +1604,11 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks_returned: wantTasks ? tasks.length : 0
|
||||
},
|
||||
next: "Pass project_id (or task_id) to netx__getBizMonitorContext; then listBizMonitorBatches for batch_id / run_id."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
function slimCutoverBatch(row) {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
project_id: row.project_id,
|
||||
batch_label: row.batch_label,
|
||||
|
|
@ -1594,12 +1620,12 @@ function slimCutoverBatch(row) {
|
|||
note: row.note,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimCollectBatch(row, taskId = "") {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
task_id: row.task_id || taskId,
|
||||
task_id: row.task_id || taskId || undefined,
|
||||
status: row.status,
|
||||
ne_name: row.ne_name,
|
||||
command_count: row.command_count,
|
||||
|
|
@ -1609,12 +1635,12 @@ function slimCollectBatch(row, taskId = "") {
|
|||
message: row.message,
|
||||
started_at: row.started_at,
|
||||
ended_at: row.ended_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimEvalRun(row) {
|
||||
const summary = asRecord(row.summary);
|
||||
const progress = asRecord(summary.progress);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
batch_id: row.batch_id,
|
||||
purpose: row.purpose,
|
||||
|
|
@ -1624,7 +1650,7 @@ function slimEvalRun(row) {
|
|||
anomaly: summary.anomaly,
|
||||
progress_ok: progress.ok ?? summary.progress_ok,
|
||||
progress_total: progress.total ?? summary.progress_total
|
||||
};
|
||||
});
|
||||
}
|
||||
async function listBizMonitorBatches(client, args, signal) {
|
||||
const projectId = str2(args, "project_id").trim();
|
||||
|
|
@ -1733,7 +1759,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
}
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
project_id: projectId || undefined,
|
||||
task_id: taskId || undefined,
|
||||
|
|
@ -1747,7 +1773,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
runs: runs.length
|
||||
},
|
||||
next: wantCutover ? "Use cutover batch id with netx__getBizMonitorBoard / listBizMonitorBatches(kind=runs). Collect batch id → netx__getBizCollectBatch." : wantCollect ? "Pass collect batch id to netx__getBizCollectBatch / getBizCollectCommandRaw." : "Pass run_id to netx__getBizMonitorDiffs or getBizMonitorBoard(run_id)."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
async function getBizMonitorContext(client, args, signal) {
|
||||
|
|
@ -2491,10 +2517,11 @@ function tool2(name, description, parameters, handler, getClient, timeoutMs) {
|
|||
isConcurrencySafe: () => true,
|
||||
async execute(args, exec) {
|
||||
const result = await handler(getClient(), args, exec.signal);
|
||||
if (result.ok === false) {
|
||||
throw new Error(JSON.stringify(result));
|
||||
const safe = toLosslessJson(result);
|
||||
if (result.ok === false || safe.ok === false) {
|
||||
throw new Error(JSON.stringify(safe));
|
||||
}
|
||||
return result;
|
||||
return safe;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -737,6 +737,32 @@ function watchKbContext(listener) {
|
|||
};
|
||||
}
|
||||
|
||||
// src/netx/json-safe.ts
|
||||
function toLosslessJson(value) {
|
||||
try {
|
||||
const text = JSON.stringify(value);
|
||||
if (text === undefined) {
|
||||
return { ok: false, error: "tool_result_not_json", detail: "undefined_root" };
|
||||
}
|
||||
const parsed = JSON.parse(text);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return { ok: true, data: { value: parsed } };
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
return { ok: false, error: "tool_result_not_json", detail: detail.slice(0, 400) };
|
||||
}
|
||||
}
|
||||
function omitUndefined(record) {
|
||||
const out = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
if (value !== undefined)
|
||||
out[key] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// src/netx/kb-local-tools.ts
|
||||
var str = (description) => ({ type: "string", ...description ? { description } : {} });
|
||||
var bool = (description) => ({ type: "boolean", ...description ? { description } : {} });
|
||||
|
|
@ -766,7 +792,7 @@ function tool(name, description, parameters, execute) {
|
|||
isConcurrencySafe: () => false,
|
||||
async execute(args) {
|
||||
try {
|
||||
return await execute(args);
|
||||
return toLosslessJson(await execute(args));
|
||||
} catch (error) {
|
||||
throw new Error(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
|
|
@ -1481,7 +1507,7 @@ function taskBriefNe(brief) {
|
|||
}
|
||||
function slimMigrationProject(row) {
|
||||
const mt = asRecord(row.monitor_template);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
status: row.status,
|
||||
|
|
@ -1498,7 +1524,7 @@ function slimMigrationProject(row) {
|
|||
hf_start_at: row.hf_start_at,
|
||||
hf_end_at: row.hf_end_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function matchesBizMonitorQ(row, q) {
|
||||
if (!q)
|
||||
|
|
@ -1567,7 +1593,7 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks = tasks.slice(0, limit);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
projects: wantProjects ? projects : undefined,
|
||||
tasks: wantTasks ? tasks : undefined,
|
||||
|
|
@ -1578,11 +1604,11 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks_returned: wantTasks ? tasks.length : 0
|
||||
},
|
||||
next: "Pass project_id (or task_id) to netx__getBizMonitorContext; then listBizMonitorBatches for batch_id / run_id."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
function slimCutoverBatch(row) {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
project_id: row.project_id,
|
||||
batch_label: row.batch_label,
|
||||
|
|
@ -1594,12 +1620,12 @@ function slimCutoverBatch(row) {
|
|||
note: row.note,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimCollectBatch(row, taskId = "") {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
task_id: row.task_id || taskId,
|
||||
task_id: row.task_id || taskId || undefined,
|
||||
status: row.status,
|
||||
ne_name: row.ne_name,
|
||||
command_count: row.command_count,
|
||||
|
|
@ -1609,12 +1635,12 @@ function slimCollectBatch(row, taskId = "") {
|
|||
message: row.message,
|
||||
started_at: row.started_at,
|
||||
ended_at: row.ended_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimEvalRun(row) {
|
||||
const summary = asRecord(row.summary);
|
||||
const progress = asRecord(summary.progress);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
batch_id: row.batch_id,
|
||||
purpose: row.purpose,
|
||||
|
|
@ -1624,7 +1650,7 @@ function slimEvalRun(row) {
|
|||
anomaly: summary.anomaly,
|
||||
progress_ok: progress.ok ?? summary.progress_ok,
|
||||
progress_total: progress.total ?? summary.progress_total
|
||||
};
|
||||
});
|
||||
}
|
||||
async function listBizMonitorBatches(client, args, signal) {
|
||||
const projectId = str2(args, "project_id").trim();
|
||||
|
|
@ -1733,7 +1759,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
}
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
project_id: projectId || undefined,
|
||||
task_id: taskId || undefined,
|
||||
|
|
@ -1747,7 +1773,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
runs: runs.length
|
||||
},
|
||||
next: wantCutover ? "Use cutover batch id with netx__getBizMonitorBoard / listBizMonitorBatches(kind=runs). Collect batch id → netx__getBizCollectBatch." : wantCollect ? "Pass collect batch id to netx__getBizCollectBatch / getBizCollectCommandRaw." : "Pass run_id to netx__getBizMonitorDiffs or getBizMonitorBoard(run_id)."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
async function getBizMonitorContext(client, args, signal) {
|
||||
|
|
@ -2491,10 +2517,11 @@ function tool2(name, description, parameters, handler, getClient, timeoutMs) {
|
|||
isConcurrencySafe: () => true,
|
||||
async execute(args, exec) {
|
||||
const result = await handler(getClient(), args, exec.signal);
|
||||
if (result.ok === false) {
|
||||
throw new Error(JSON.stringify(result));
|
||||
const safe = toLosslessJson(result);
|
||||
if (result.ok === false || safe.ok === false) {
|
||||
throw new Error(JSON.stringify(safe));
|
||||
}
|
||||
return result;
|
||||
return safe;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -737,6 +737,32 @@ function watchKbContext(listener) {
|
|||
};
|
||||
}
|
||||
|
||||
// src/netx/json-safe.ts
|
||||
function toLosslessJson(value) {
|
||||
try {
|
||||
const text = JSON.stringify(value);
|
||||
if (text === undefined) {
|
||||
return { ok: false, error: "tool_result_not_json", detail: "undefined_root" };
|
||||
}
|
||||
const parsed = JSON.parse(text);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return { ok: true, data: { value: parsed } };
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
return { ok: false, error: "tool_result_not_json", detail: detail.slice(0, 400) };
|
||||
}
|
||||
}
|
||||
function omitUndefined(record) {
|
||||
const out = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
if (value !== undefined)
|
||||
out[key] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// src/netx/kb-local-tools.ts
|
||||
var str = (description) => ({ type: "string", ...description ? { description } : {} });
|
||||
var bool = (description) => ({ type: "boolean", ...description ? { description } : {} });
|
||||
|
|
@ -766,7 +792,7 @@ function tool(name, description, parameters, execute) {
|
|||
isConcurrencySafe: () => false,
|
||||
async execute(args) {
|
||||
try {
|
||||
return await execute(args);
|
||||
return toLosslessJson(await execute(args));
|
||||
} catch (error) {
|
||||
throw new Error(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
|
|
@ -1481,7 +1507,7 @@ function taskBriefNe(brief) {
|
|||
}
|
||||
function slimMigrationProject(row) {
|
||||
const mt = asRecord(row.monitor_template);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
status: row.status,
|
||||
|
|
@ -1498,7 +1524,7 @@ function slimMigrationProject(row) {
|
|||
hf_start_at: row.hf_start_at,
|
||||
hf_end_at: row.hf_end_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function matchesBizMonitorQ(row, q) {
|
||||
if (!q)
|
||||
|
|
@ -1567,7 +1593,7 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks = tasks.slice(0, limit);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
projects: wantProjects ? projects : undefined,
|
||||
tasks: wantTasks ? tasks : undefined,
|
||||
|
|
@ -1578,11 +1604,11 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks_returned: wantTasks ? tasks.length : 0
|
||||
},
|
||||
next: "Pass project_id (or task_id) to netx__getBizMonitorContext; then listBizMonitorBatches for batch_id / run_id."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
function slimCutoverBatch(row) {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
project_id: row.project_id,
|
||||
batch_label: row.batch_label,
|
||||
|
|
@ -1594,12 +1620,12 @@ function slimCutoverBatch(row) {
|
|||
note: row.note,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimCollectBatch(row, taskId = "") {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
task_id: row.task_id || taskId,
|
||||
task_id: row.task_id || taskId || undefined,
|
||||
status: row.status,
|
||||
ne_name: row.ne_name,
|
||||
command_count: row.command_count,
|
||||
|
|
@ -1609,12 +1635,12 @@ function slimCollectBatch(row, taskId = "") {
|
|||
message: row.message,
|
||||
started_at: row.started_at,
|
||||
ended_at: row.ended_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimEvalRun(row) {
|
||||
const summary = asRecord(row.summary);
|
||||
const progress = asRecord(summary.progress);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
batch_id: row.batch_id,
|
||||
purpose: row.purpose,
|
||||
|
|
@ -1624,7 +1650,7 @@ function slimEvalRun(row) {
|
|||
anomaly: summary.anomaly,
|
||||
progress_ok: progress.ok ?? summary.progress_ok,
|
||||
progress_total: progress.total ?? summary.progress_total
|
||||
};
|
||||
});
|
||||
}
|
||||
async function listBizMonitorBatches(client, args, signal) {
|
||||
const projectId = str2(args, "project_id").trim();
|
||||
|
|
@ -1733,7 +1759,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
}
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
project_id: projectId || undefined,
|
||||
task_id: taskId || undefined,
|
||||
|
|
@ -1747,7 +1773,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
runs: runs.length
|
||||
},
|
||||
next: wantCutover ? "Use cutover batch id with netx__getBizMonitorBoard / listBizMonitorBatches(kind=runs). Collect batch id → netx__getBizCollectBatch." : wantCollect ? "Pass collect batch id to netx__getBizCollectBatch / getBizCollectCommandRaw." : "Pass run_id to netx__getBizMonitorDiffs or getBizMonitorBoard(run_id)."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
async function getBizMonitorContext(client, args, signal) {
|
||||
|
|
@ -2491,10 +2517,11 @@ function tool2(name, description, parameters, handler, getClient, timeoutMs) {
|
|||
isConcurrencySafe: () => true,
|
||||
async execute(args, exec) {
|
||||
const result = await handler(getClient(), args, exec.signal);
|
||||
if (result.ok === false) {
|
||||
throw new Error(JSON.stringify(result));
|
||||
const safe = toLosslessJson(result);
|
||||
if (result.ok === false || safe.ok === false) {
|
||||
throw new Error(JSON.stringify(safe));
|
||||
}
|
||||
return result;
|
||||
return safe;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -737,6 +737,32 @@ function watchKbContext(listener) {
|
|||
};
|
||||
}
|
||||
|
||||
// src/netx/json-safe.ts
|
||||
function toLosslessJson(value) {
|
||||
try {
|
||||
const text = JSON.stringify(value);
|
||||
if (text === undefined) {
|
||||
return { ok: false, error: "tool_result_not_json", detail: "undefined_root" };
|
||||
}
|
||||
const parsed = JSON.parse(text);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return { ok: true, data: { value: parsed } };
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
return { ok: false, error: "tool_result_not_json", detail: detail.slice(0, 400) };
|
||||
}
|
||||
}
|
||||
function omitUndefined(record) {
|
||||
const out = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
if (value !== undefined)
|
||||
out[key] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// src/netx/kb-local-tools.ts
|
||||
var str = (description) => ({ type: "string", ...description ? { description } : {} });
|
||||
var bool = (description) => ({ type: "boolean", ...description ? { description } : {} });
|
||||
|
|
@ -766,7 +792,7 @@ function tool(name, description, parameters, execute) {
|
|||
isConcurrencySafe: () => false,
|
||||
async execute(args) {
|
||||
try {
|
||||
return await execute(args);
|
||||
return toLosslessJson(await execute(args));
|
||||
} catch (error) {
|
||||
throw new Error(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
|
|
@ -1481,7 +1507,7 @@ function taskBriefNe(brief) {
|
|||
}
|
||||
function slimMigrationProject(row) {
|
||||
const mt = asRecord(row.monitor_template);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
status: row.status,
|
||||
|
|
@ -1498,7 +1524,7 @@ function slimMigrationProject(row) {
|
|||
hf_start_at: row.hf_start_at,
|
||||
hf_end_at: row.hf_end_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function matchesBizMonitorQ(row, q) {
|
||||
if (!q)
|
||||
|
|
@ -1567,7 +1593,7 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks = tasks.slice(0, limit);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
projects: wantProjects ? projects : undefined,
|
||||
tasks: wantTasks ? tasks : undefined,
|
||||
|
|
@ -1578,11 +1604,11 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks_returned: wantTasks ? tasks.length : 0
|
||||
},
|
||||
next: "Pass project_id (or task_id) to netx__getBizMonitorContext; then listBizMonitorBatches for batch_id / run_id."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
function slimCutoverBatch(row) {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
project_id: row.project_id,
|
||||
batch_label: row.batch_label,
|
||||
|
|
@ -1594,12 +1620,12 @@ function slimCutoverBatch(row) {
|
|||
note: row.note,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimCollectBatch(row, taskId = "") {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
task_id: row.task_id || taskId,
|
||||
task_id: row.task_id || taskId || undefined,
|
||||
status: row.status,
|
||||
ne_name: row.ne_name,
|
||||
command_count: row.command_count,
|
||||
|
|
@ -1609,12 +1635,12 @@ function slimCollectBatch(row, taskId = "") {
|
|||
message: row.message,
|
||||
started_at: row.started_at,
|
||||
ended_at: row.ended_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimEvalRun(row) {
|
||||
const summary = asRecord(row.summary);
|
||||
const progress = asRecord(summary.progress);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
batch_id: row.batch_id,
|
||||
purpose: row.purpose,
|
||||
|
|
@ -1624,7 +1650,7 @@ function slimEvalRun(row) {
|
|||
anomaly: summary.anomaly,
|
||||
progress_ok: progress.ok ?? summary.progress_ok,
|
||||
progress_total: progress.total ?? summary.progress_total
|
||||
};
|
||||
});
|
||||
}
|
||||
async function listBizMonitorBatches(client, args, signal) {
|
||||
const projectId = str2(args, "project_id").trim();
|
||||
|
|
@ -1733,7 +1759,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
}
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
project_id: projectId || undefined,
|
||||
task_id: taskId || undefined,
|
||||
|
|
@ -1747,7 +1773,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
runs: runs.length
|
||||
},
|
||||
next: wantCutover ? "Use cutover batch id with netx__getBizMonitorBoard / listBizMonitorBatches(kind=runs). Collect batch id → netx__getBizCollectBatch." : wantCollect ? "Pass collect batch id to netx__getBizCollectBatch / getBizCollectCommandRaw." : "Pass run_id to netx__getBizMonitorDiffs or getBizMonitorBoard(run_id)."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
async function getBizMonitorContext(client, args, signal) {
|
||||
|
|
@ -2491,10 +2517,11 @@ function tool2(name, description, parameters, handler, getClient, timeoutMs) {
|
|||
isConcurrencySafe: () => true,
|
||||
async execute(args, exec) {
|
||||
const result = await handler(getClient(), args, exec.signal);
|
||||
if (result.ok === false) {
|
||||
throw new Error(JSON.stringify(result));
|
||||
const safe = toLosslessJson(result);
|
||||
if (result.ok === false || safe.ok === false) {
|
||||
throw new Error(JSON.stringify(safe));
|
||||
}
|
||||
return result;
|
||||
return safe;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
61
lib/index.js
61
lib/index.js
|
|
@ -1599,6 +1599,32 @@ function resetKbContext() {
|
|||
applyKbEnv(unconfiguredKbSnapshot());
|
||||
}
|
||||
|
||||
// src/netx/json-safe.ts
|
||||
function toLosslessJson(value) {
|
||||
try {
|
||||
const text = JSON.stringify(value);
|
||||
if (text === undefined) {
|
||||
return { ok: false, error: "tool_result_not_json", detail: "undefined_root" };
|
||||
}
|
||||
const parsed = JSON.parse(text);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return { ok: true, data: { value: parsed } };
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
return { ok: false, error: "tool_result_not_json", detail: detail.slice(0, 400) };
|
||||
}
|
||||
}
|
||||
function omitUndefined(record) {
|
||||
const out = {};
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
if (value !== undefined)
|
||||
out[key] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// src/netx/kb-local-tools.ts
|
||||
var str = (description) => ({ type: "string", ...description ? { description } : {} });
|
||||
var bool = (description) => ({ type: "boolean", ...description ? { description } : {} });
|
||||
|
|
@ -1628,7 +1654,7 @@ function tool(name, description, parameters, execute) {
|
|||
isConcurrencySafe: () => false,
|
||||
async execute(args) {
|
||||
try {
|
||||
return await execute(args);
|
||||
return toLosslessJson(await execute(args));
|
||||
} catch (error) {
|
||||
throw new Error(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
|
|
@ -3740,7 +3766,7 @@ function taskBriefNe(brief) {
|
|||
}
|
||||
function slimMigrationProject(row) {
|
||||
const mt = asRecord(row.monitor_template);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
status: row.status,
|
||||
|
|
@ -3757,7 +3783,7 @@ function slimMigrationProject(row) {
|
|||
hf_start_at: row.hf_start_at,
|
||||
hf_end_at: row.hf_end_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function matchesBizMonitorQ(row, q) {
|
||||
if (!q)
|
||||
|
|
@ -3826,7 +3852,7 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks = tasks.slice(0, limit);
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
projects: wantProjects ? projects : undefined,
|
||||
tasks: wantTasks ? tasks : undefined,
|
||||
|
|
@ -3837,11 +3863,11 @@ async function listBizMonitors(client, args, signal) {
|
|||
tasks_returned: wantTasks ? tasks.length : 0
|
||||
},
|
||||
next: "Pass project_id (or task_id) to netx__getBizMonitorContext; then listBizMonitorBatches for batch_id / run_id."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
function slimCutoverBatch(row) {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
project_id: row.project_id,
|
||||
batch_label: row.batch_label,
|
||||
|
|
@ -3853,12 +3879,12 @@ function slimCutoverBatch(row) {
|
|||
note: row.note,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimCollectBatch(row, taskId = "") {
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
task_id: row.task_id || taskId,
|
||||
task_id: row.task_id || taskId || undefined,
|
||||
status: row.status,
|
||||
ne_name: row.ne_name,
|
||||
command_count: row.command_count,
|
||||
|
|
@ -3868,12 +3894,12 @@ function slimCollectBatch(row, taskId = "") {
|
|||
message: row.message,
|
||||
started_at: row.started_at,
|
||||
ended_at: row.ended_at
|
||||
};
|
||||
});
|
||||
}
|
||||
function slimEvalRun(row) {
|
||||
const summary = asRecord(row.summary);
|
||||
const progress = asRecord(summary.progress);
|
||||
return {
|
||||
return omitUndefined({
|
||||
id: row.id,
|
||||
batch_id: row.batch_id,
|
||||
purpose: row.purpose,
|
||||
|
|
@ -3883,7 +3909,7 @@ function slimEvalRun(row) {
|
|||
anomaly: summary.anomaly,
|
||||
progress_ok: progress.ok ?? summary.progress_ok,
|
||||
progress_total: progress.total ?? summary.progress_total
|
||||
};
|
||||
});
|
||||
}
|
||||
async function listBizMonitorBatches(client, args, signal) {
|
||||
const projectId = str2(args, "project_id").trim();
|
||||
|
|
@ -3992,7 +4018,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
}
|
||||
return {
|
||||
ok: true,
|
||||
data: {
|
||||
data: omitUndefined({
|
||||
kind,
|
||||
project_id: projectId || undefined,
|
||||
task_id: taskId || undefined,
|
||||
|
|
@ -4006,7 +4032,7 @@ async function listBizMonitorBatches(client, args, signal) {
|
|||
runs: runs.length
|
||||
},
|
||||
next: wantCutover ? "Use cutover batch id with netx__getBizMonitorBoard / listBizMonitorBatches(kind=runs). Collect batch id → netx__getBizCollectBatch." : wantCollect ? "Pass collect batch id to netx__getBizCollectBatch / getBizCollectCommandRaw." : "Pass run_id to netx__getBizMonitorDiffs or getBizMonitorBoard(run_id)."
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
async function getBizMonitorContext(client, args, signal) {
|
||||
|
|
@ -4750,10 +4776,11 @@ function tool2(name, description, parameters, handler, getClient, timeoutMs) {
|
|||
isConcurrencySafe: () => true,
|
||||
async execute(args, exec) {
|
||||
const result = await handler(getClient(), args, exec.signal);
|
||||
if (result.ok === false) {
|
||||
throw new Error(JSON.stringify(result));
|
||||
const safe = toLosslessJson(result);
|
||||
if (result.ok === false || safe.ok === false) {
|
||||
throw new Error(JSON.stringify(safe));
|
||||
}
|
||||
return result;
|
||||
return safe;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue