@erdoai/cli 0.121.0 → 0.124.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/index.js +63 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -186,7 +186,7 @@ async function rawRequest(baseURL, token, orgId, projectId, method, path, body,
|
|
|
186
186
|
continue;
|
|
187
187
|
}
|
|
188
188
|
if (!retryNetworkFailures) {
|
|
189
|
-
throw new ErdoNetworkError(`${netErr.message}. The
|
|
189
|
+
throw new ErdoNetworkError(`${netErr.message}. The request may have succeeded; inspect the affected resource before retrying.`, netErr);
|
|
190
190
|
}
|
|
191
191
|
throw netErr;
|
|
192
192
|
}
|
|
@@ -1200,6 +1200,12 @@ var ErdoClient = class {
|
|
|
1200
1200
|
updateDatasetSchema(slug, input) {
|
|
1201
1201
|
return this.request("POST", `/v1/datasets/${encodeURIComponent(slug)}/schema`, input);
|
|
1202
1202
|
}
|
|
1203
|
+
// Dataset row writes are deliberately never replayed after a network
|
|
1204
|
+
// failure: the server may have committed the rows before the response was
|
|
1205
|
+
// lost, and repeating an append or upsert can change the result.
|
|
1206
|
+
writeDatasetRows(slug, input) {
|
|
1207
|
+
return this.request("POST", `/v1/datasets/${encodeURIComponent(slug)}/rows`, input, false);
|
|
1208
|
+
}
|
|
1203
1209
|
// The endpoint's field is `question` (QueryDataNaturalLanguageInput). Sending // The endpoint's field is `question` (QueryDataNaturalLanguageInput). Sending
|
|
1204
1210
|
// `query` made every `erdo datasets query` fail with "question is required".
|
|
1205
1211
|
//
|
|
@@ -1714,6 +1720,7 @@ var ErdoClient = class {
|
|
|
1714
1720
|
// --- agent runs ---
|
|
1715
1721
|
listAgentRuns(opts) {
|
|
1716
1722
|
const params = new URLSearchParams();
|
|
1723
|
+
if (opts.invocation) params.set("invocation_id", opts.invocation);
|
|
1717
1724
|
if (opts.agent) params.set("agent_key", opts.agent);
|
|
1718
1725
|
if (opts.thread) params.set("thread_id", opts.thread);
|
|
1719
1726
|
if (opts.status) params.set("status", opts.status);
|
|
@@ -4184,7 +4191,7 @@ agentCmd.command("messages <threadId>").description("Show a thread's messages (r
|
|
|
4184
4191
|
}
|
|
4185
4192
|
});
|
|
4186
4193
|
var runsCmd = program.command("runs").description("Inspect agent runs");
|
|
4187
|
-
runsCmd.command("list").description("List agent runs
|
|
4194
|
+
runsCmd.command("list").description("List agent runs; select an exact invocation, optionally constrained by agent OR thread").option("--invocation <id>", "select the exact root run for an invocation").option("-a, --agent <key>", "filter by agent key").option("-t, --thread <id>", "filter to a thread").option("-s, --status <status>", "filter by status (running, completed, failed, cancelled, pending)").option("-l, --limit <n>", "max runs", (v) => parseInt(v, 10)).action(async (opts) => {
|
|
4188
4195
|
try {
|
|
4189
4196
|
const { runs } = await new ErdoClient().listAgentRuns(opts);
|
|
4190
4197
|
for (const r of runs) console.log(`${r.id} ${r.status} ${r.agent_key}`);
|
|
@@ -4192,13 +4199,13 @@ runsCmd.command("list").description("List agent runs (filter by agent OR thread
|
|
|
4192
4199
|
fail(e);
|
|
4193
4200
|
}
|
|
4194
4201
|
});
|
|
4195
|
-
runsCmd.command("get <id>").description("Show an agent run (status, output, trace metadata)").option("--resources", "also show the skills, knowledge and entities the run used").option("--steps", "also show the run's iterations, tool calls and sub-agent invocations").action(async (id, opts) => {
|
|
4202
|
+
runsCmd.command("get <id>").description("Show an agent run (status, output, trace metadata)").option("--resources", "also show the skills, knowledge and entities the run used").option("--steps", "also show the run's iterations, tool calls and sub-agent invocations").option("--json", "print the full JSON response, including requested resources and steps").action(async (id, opts) => {
|
|
4196
4203
|
try {
|
|
4197
4204
|
const include = [];
|
|
4198
4205
|
if (opts.resources) include.push("resources");
|
|
4199
4206
|
if (opts.steps) include.push("steps");
|
|
4200
4207
|
const detail = await new ErdoClient().getAgentRun(id, include);
|
|
4201
|
-
if (include.length === 0) {
|
|
4208
|
+
if (opts.json || include.length === 0) {
|
|
4202
4209
|
print(detail);
|
|
4203
4210
|
return;
|
|
4204
4211
|
}
|
|
@@ -6658,6 +6665,53 @@ datasetsCmd.command("purposes").description(
|
|
|
6658
6665
|
fail(e);
|
|
6659
6666
|
}
|
|
6660
6667
|
});
|
|
6668
|
+
datasetsCmd.command("write <slug>").description(
|
|
6669
|
+
"Write rows to a dataset. Without --key-column rows append. File and writable PostgreSQL datasets support keyed replace or merge. ClickHouse-backed writes always append, even with a key, and refuse merge."
|
|
6670
|
+
).requiredOption("--rows <json-or-@file>", "JSON array of row objects, or @path to a JSON file").option("--key-column <columns>", "non-blank key column, or comma-separated columns for a composite key").option("--write-mode <replace|merge>", "replace matching fields (files clear omitted fields; PostgreSQL updates batch columns), or merge; either explicit mode requires --key-column").option("--overwrite-columns <csv>", "comma-separated columns merge mode may overwrite").action(
|
|
6671
|
+
async (slug, opts) => {
|
|
6672
|
+
try {
|
|
6673
|
+
const rawRows = readMaybeFile(opts.rows);
|
|
6674
|
+
let parsed;
|
|
6675
|
+
try {
|
|
6676
|
+
parsed = JSON.parse(rawRows ?? "");
|
|
6677
|
+
} catch (error) {
|
|
6678
|
+
throw new Error(`--rows must contain valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
6679
|
+
}
|
|
6680
|
+
if (!Array.isArray(parsed) || parsed.some((row) => row === null || typeof row !== "object" || Array.isArray(row))) {
|
|
6681
|
+
throw new Error("--rows must contain a JSON array of non-null objects");
|
|
6682
|
+
}
|
|
6683
|
+
const writeMode = opts.writeMode;
|
|
6684
|
+
if (writeMode !== void 0 && writeMode !== "replace" && writeMode !== "merge") {
|
|
6685
|
+
throw new Error('--write-mode must be "replace" or "merge"');
|
|
6686
|
+
}
|
|
6687
|
+
if (writeMode !== void 0 && !opts.keyColumn?.trim()) {
|
|
6688
|
+
throw new Error(`--write-mode "${writeMode}" requires a non-blank --key-column`);
|
|
6689
|
+
}
|
|
6690
|
+
if (opts.keyColumn !== void 0 && !opts.keyColumn.split(",").some((column) => column.trim())) {
|
|
6691
|
+
throw new Error("--key-column must name at least one non-blank column");
|
|
6692
|
+
}
|
|
6693
|
+
let overwriteColumns;
|
|
6694
|
+
if (opts.overwriteColumns !== void 0) {
|
|
6695
|
+
if (writeMode !== "merge") {
|
|
6696
|
+
throw new Error("--overwrite-columns requires --write-mode merge");
|
|
6697
|
+
}
|
|
6698
|
+
overwriteColumns = opts.overwriteColumns.split(",").map((column) => column.trim());
|
|
6699
|
+
if (overwriteColumns.some((column) => !column)) {
|
|
6700
|
+
throw new Error("--overwrite-columns must not contain empty column names");
|
|
6701
|
+
}
|
|
6702
|
+
}
|
|
6703
|
+
const result = await new ErdoClient().writeDatasetRows(slug, {
|
|
6704
|
+
rows: parsed,
|
|
6705
|
+
...opts.keyColumn !== void 0 ? { key_column: opts.keyColumn } : {},
|
|
6706
|
+
...writeMode !== void 0 ? { write_mode: writeMode } : {},
|
|
6707
|
+
...overwriteColumns !== void 0 ? { overwrite_columns: overwriteColumns } : {}
|
|
6708
|
+
});
|
|
6709
|
+
print(result);
|
|
6710
|
+
} catch (e) {
|
|
6711
|
+
fail(e);
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
);
|
|
6661
6715
|
function readSchemaFile(path) {
|
|
6662
6716
|
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
6663
6717
|
const schema = Array.isArray(parsed) ? { columns: parsed } : parsed;
|
|
@@ -7096,7 +7150,7 @@ refreshCmd.command("set <slug>").description(
|
|
|
7096
7150
|
).option(
|
|
7097
7151
|
"--mode <replace|upsert>",
|
|
7098
7152
|
"replace overwrites every row with what the recipe returned; upsert merges by --key-column and keeps rows outside the returned window. Omit it and you get upsert when you passed --key-column and replace when you did not, since a key column is only meaningful to a merge"
|
|
7099
|
-
).option("--key-column <c>", "
|
|
7153
|
+
).option("--key-column <c>", "non-blank column, or comma-separated columns, an upsert merges on; required with --mode upsert").option(
|
|
7100
7154
|
"--schedule <cron>",
|
|
7101
7155
|
"a cron expression to run the refresh on a fixed cadence. Omit it and the refresh runs on view instead \u2014 cheaper, because it never runs while nobody is looking"
|
|
7102
7156
|
).option("--timezone <tz>", "IANA timezone the cron expression is read in (default UTC)").option(
|
|
@@ -7146,6 +7200,10 @@ refreshCmd.command("set <slug>").description(
|
|
|
7146
7200
|
fail(new Error("--mode must be replace or upsert"));
|
|
7147
7201
|
return;
|
|
7148
7202
|
}
|
|
7203
|
+
if (opts.keyColumn !== void 0 && !opts.keyColumn.split(",").some((column) => column.trim())) {
|
|
7204
|
+
fail(new Error("--key-column must name at least one non-blank column"));
|
|
7205
|
+
return;
|
|
7206
|
+
}
|
|
7149
7207
|
if (opts.mode === "upsert" && !opts.keyColumn) {
|
|
7150
7208
|
fail(new Error("--mode upsert needs --key-column <c>: the column the merge keys on"));
|
|
7151
7209
|
return;
|