vent-hq 0.13.1 → 0.13.2
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.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import * as path from "node:path";
|
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
16
|
var CONFIG_DIR = path.join(homedir(), ".vent");
|
|
17
17
|
var CREDENTIALS_FILE = path.join(CONFIG_DIR, "credentials");
|
|
18
|
-
var API_BASE =
|
|
18
|
+
var API_BASE = "https://api.venthq.dev";
|
|
19
19
|
var DASHBOARD_URL = process.env.VENT_DASHBOARD_URL ?? "https://venthq.dev";
|
|
20
20
|
async function loadAccessToken() {
|
|
21
21
|
if (process.env.VENT_ACCESS_TOKEN) return process.env.VENT_ACCESS_TOKEN;
|
|
@@ -80,6 +80,84 @@ async function ensurePlatformConnection(apiKey, platform) {
|
|
|
80
80
|
return res.json();
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
// src/lib/sse.ts
|
|
84
|
+
var MAX_RETRIES = 5;
|
|
85
|
+
var RETRY_DELAY_MS = 2e3;
|
|
86
|
+
async function* streamRunEvents(runId, apiKey, signal) {
|
|
87
|
+
const url = `${API_BASE}/runs/${runId}/stream`;
|
|
88
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
89
|
+
let retries = 0;
|
|
90
|
+
while (retries <= MAX_RETRIES) {
|
|
91
|
+
if (retries > 0) {
|
|
92
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
93
|
+
}
|
|
94
|
+
let res;
|
|
95
|
+
try {
|
|
96
|
+
res = await fetch(url, {
|
|
97
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
98
|
+
signal
|
|
99
|
+
});
|
|
100
|
+
} catch (err) {
|
|
101
|
+
if (err.name === "AbortError") throw err;
|
|
102
|
+
retries++;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!res.ok) {
|
|
106
|
+
const body = await res.text();
|
|
107
|
+
throw new Error(`SSE stream failed (${res.status}): ${body}`);
|
|
108
|
+
}
|
|
109
|
+
if (!res.body) {
|
|
110
|
+
throw new Error("SSE stream returned no body");
|
|
111
|
+
}
|
|
112
|
+
const reader = res.body.getReader();
|
|
113
|
+
const decoder = new TextDecoder();
|
|
114
|
+
let buffer = "";
|
|
115
|
+
try {
|
|
116
|
+
while (true) {
|
|
117
|
+
let readResult;
|
|
118
|
+
try {
|
|
119
|
+
readResult = await reader.read();
|
|
120
|
+
} catch (err) {
|
|
121
|
+
if (err.name === "AbortError") throw err;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
const { done, value } = readResult;
|
|
125
|
+
if (done) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
129
|
+
buffer += chunk;
|
|
130
|
+
const lines = buffer.split("\n");
|
|
131
|
+
buffer = lines.pop();
|
|
132
|
+
for (const line of lines) {
|
|
133
|
+
if (line.startsWith("data: ")) {
|
|
134
|
+
const raw = line.slice(6);
|
|
135
|
+
try {
|
|
136
|
+
const event = JSON.parse(raw);
|
|
137
|
+
if (event.id && seenIds.has(event.id)) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (event.id) seenIds.add(event.id);
|
|
141
|
+
yield event;
|
|
142
|
+
if (event.event_type === "run_complete") {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} finally {
|
|
151
|
+
reader.releaseLock();
|
|
152
|
+
}
|
|
153
|
+
retries++;
|
|
154
|
+
}
|
|
155
|
+
yield {
|
|
156
|
+
event_type: "error",
|
|
157
|
+
message: `Stream lost after ${MAX_RETRIES} reconnect attempts without receiving run_complete`
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
83
161
|
// src/lib/output.ts
|
|
84
162
|
import { writeFileSync } from "node:fs";
|
|
85
163
|
|
|
@@ -4432,7 +4510,7 @@ function formatConversationResult(raw, options = {}) {
|
|
|
4432
4510
|
const r = raw;
|
|
4433
4511
|
if (typeof r.caller_prompt !== "string") return null;
|
|
4434
4512
|
const verbose = options.verbose ?? false;
|
|
4435
|
-
const
|
|
4513
|
+
const debug = verbose ? formatDebug(r) : void 0;
|
|
4436
4514
|
const warnings = dedupeStrings([
|
|
4437
4515
|
...formatProviderWarningMessages(r.call_metadata?.provider_warnings)
|
|
4438
4516
|
]);
|
|
@@ -4449,7 +4527,7 @@ function formatConversationResult(raw, options = {}) {
|
|
|
4449
4527
|
};
|
|
4450
4528
|
if (warnings.length > 0) result.warnings = warnings;
|
|
4451
4529
|
if (verbose) result.caller_prompt = r.caller_prompt;
|
|
4452
|
-
if (
|
|
4530
|
+
if (debug) result.debug = debug;
|
|
4453
4531
|
return result;
|
|
4454
4532
|
}
|
|
4455
4533
|
function formatTranscript(turns, options) {
|
|
@@ -4463,7 +4541,7 @@ function formatTranscript(turns, options) {
|
|
|
4463
4541
|
if (t.ttfw_ms != null) turn.ttfw_ms = t.ttfw_ms;
|
|
4464
4542
|
if (t.audio_duration_ms != null) turn.audio_duration_ms = t.audio_duration_ms;
|
|
4465
4543
|
if (options.verbose) {
|
|
4466
|
-
const
|
|
4544
|
+
const debug = compactUnknownRecord({
|
|
4467
4545
|
timestamp_ms: t.timestamp_ms,
|
|
4468
4546
|
caller_decision_mode: t.caller_decision_mode,
|
|
4469
4547
|
silence_pad_ms: t.silence_pad_ms,
|
|
@@ -4473,8 +4551,8 @@ function formatTranscript(turns, options) {
|
|
|
4473
4551
|
component_latency: t.component_latency,
|
|
4474
4552
|
platform_transcript: t.platform_transcript
|
|
4475
4553
|
});
|
|
4476
|
-
if (
|
|
4477
|
-
turn.debug =
|
|
4554
|
+
if (debug && Object.keys(debug).length > 0) {
|
|
4555
|
+
turn.debug = debug;
|
|
4478
4556
|
}
|
|
4479
4557
|
}
|
|
4480
4558
|
return turn;
|
|
@@ -4613,7 +4691,7 @@ function formatCallMetadata(meta, verbose) {
|
|
|
4613
4691
|
return result;
|
|
4614
4692
|
}
|
|
4615
4693
|
function formatDebug(result) {
|
|
4616
|
-
const
|
|
4694
|
+
const debug = compactUnknownRecord({
|
|
4617
4695
|
signal_quality: result.metrics?.signal_quality,
|
|
4618
4696
|
harness_overhead: result.metrics?.harness_overhead,
|
|
4619
4697
|
provider_warnings: nonEmptyArray(result.call_metadata?.provider_warnings),
|
|
@@ -4621,7 +4699,7 @@ function formatDebug(result) {
|
|
|
4621
4699
|
observed_tool_calls: formatDebugToolCalls(result.observed_tool_calls),
|
|
4622
4700
|
provider_metadata: result.call_metadata?.provider_metadata
|
|
4623
4701
|
});
|
|
4624
|
-
return
|
|
4702
|
+
return debug && Object.keys(debug).length > 0 ? debug : void 0;
|
|
4625
4703
|
}
|
|
4626
4704
|
function formatDebugToolCalls(observed) {
|
|
4627
4705
|
if (!observed || observed.length === 0) return void 0;
|
|
@@ -4656,16 +4734,6 @@ import { createHmac, timingSafeEqual } from "node:crypto";
|
|
|
4656
4734
|
|
|
4657
4735
|
// src/lib/output.ts
|
|
4658
4736
|
var isTTY = process.stdout.isTTY;
|
|
4659
|
-
var _verbose = false;
|
|
4660
|
-
function debug(msg) {
|
|
4661
|
-
if (!_verbose) return;
|
|
4662
|
-
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
4663
|
-
stdoutSync(`[vent ${ts}] ${msg}
|
|
4664
|
-
`);
|
|
4665
|
-
}
|
|
4666
|
-
function isVerbose() {
|
|
4667
|
-
return _verbose;
|
|
4668
|
-
}
|
|
4669
4737
|
function stdoutSync(data) {
|
|
4670
4738
|
if (isTTY) {
|
|
4671
4739
|
process.stdout.write(data);
|
|
@@ -4843,141 +4911,24 @@ function printError(message) {
|
|
|
4843
4911
|
stdoutSync(line);
|
|
4844
4912
|
}
|
|
4845
4913
|
function printInfo(message, { force } = {}) {
|
|
4846
|
-
if (!force && !isTTY
|
|
4914
|
+
if (!force && !isTTY) return;
|
|
4847
4915
|
const line = blue("\u25B8") + ` ${message}
|
|
4848
4916
|
`;
|
|
4849
4917
|
stdoutSync(line);
|
|
4850
4918
|
}
|
|
4851
4919
|
function printSuccess(message, { force } = {}) {
|
|
4852
|
-
if (!force && !isTTY
|
|
4920
|
+
if (!force && !isTTY) return;
|
|
4853
4921
|
const line = green("\u2714") + ` ${message}
|
|
4854
4922
|
`;
|
|
4855
4923
|
stdoutSync(line);
|
|
4856
4924
|
}
|
|
4857
4925
|
function printWarn(message, { force } = {}) {
|
|
4858
|
-
if (!force && !isTTY
|
|
4926
|
+
if (!force && !isTTY) return;
|
|
4859
4927
|
const line = yellow("\u26A0") + ` ${message}
|
|
4860
4928
|
`;
|
|
4861
4929
|
stdoutSync(line);
|
|
4862
4930
|
}
|
|
4863
4931
|
|
|
4864
|
-
// src/lib/sse.ts
|
|
4865
|
-
function log(msg) {
|
|
4866
|
-
if (!isVerbose()) return;
|
|
4867
|
-
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
4868
|
-
const line = `[vent:sse ${ts}] ${msg}
|
|
4869
|
-
`;
|
|
4870
|
-
process.stdout.write(line);
|
|
4871
|
-
}
|
|
4872
|
-
var MAX_RETRIES = 5;
|
|
4873
|
-
var RETRY_DELAY_MS = 2e3;
|
|
4874
|
-
async function* streamRunEvents(runId, apiKey, signal) {
|
|
4875
|
-
const url = `${API_BASE}/runs/${runId}/stream`;
|
|
4876
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
4877
|
-
let retries = 0;
|
|
4878
|
-
while (retries <= MAX_RETRIES) {
|
|
4879
|
-
if (retries > 0) {
|
|
4880
|
-
log(`reconnecting (attempt ${retries}/${MAX_RETRIES}) after ${RETRY_DELAY_MS}ms\u2026`);
|
|
4881
|
-
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
4882
|
-
}
|
|
4883
|
-
log(`connecting to ${url}`);
|
|
4884
|
-
let res;
|
|
4885
|
-
try {
|
|
4886
|
-
res = await fetch(url, {
|
|
4887
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
4888
|
-
signal
|
|
4889
|
-
});
|
|
4890
|
-
} catch (err) {
|
|
4891
|
-
if (err.name === "AbortError") throw err;
|
|
4892
|
-
log(`fetch error: ${err.message}`);
|
|
4893
|
-
retries++;
|
|
4894
|
-
continue;
|
|
4895
|
-
}
|
|
4896
|
-
log(`response: status=${res.status} content-type=${res.headers.get("content-type")}`);
|
|
4897
|
-
if (!res.ok) {
|
|
4898
|
-
const body = await res.text();
|
|
4899
|
-
log(`error body: ${body}`);
|
|
4900
|
-
throw new Error(`SSE stream failed (${res.status}): ${body}`);
|
|
4901
|
-
}
|
|
4902
|
-
if (!res.body) {
|
|
4903
|
-
throw new Error("SSE stream returned no body");
|
|
4904
|
-
}
|
|
4905
|
-
const reader = res.body.getReader();
|
|
4906
|
-
const decoder = new TextDecoder();
|
|
4907
|
-
let buffer = "";
|
|
4908
|
-
let chunkCount = 0;
|
|
4909
|
-
let eventCount = 0;
|
|
4910
|
-
let gotRunComplete = false;
|
|
4911
|
-
let streamError = null;
|
|
4912
|
-
try {
|
|
4913
|
-
while (true) {
|
|
4914
|
-
let readResult;
|
|
4915
|
-
try {
|
|
4916
|
-
readResult = await reader.read();
|
|
4917
|
-
} catch (err) {
|
|
4918
|
-
if (err.name === "AbortError") throw err;
|
|
4919
|
-
streamError = err;
|
|
4920
|
-
log(`read error: ${streamError.message}`);
|
|
4921
|
-
break;
|
|
4922
|
-
}
|
|
4923
|
-
const { done, value } = readResult;
|
|
4924
|
-
if (done) {
|
|
4925
|
-
log(`stream done after ${chunkCount} chunks, ${eventCount} events`);
|
|
4926
|
-
break;
|
|
4927
|
-
}
|
|
4928
|
-
chunkCount++;
|
|
4929
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
4930
|
-
buffer += chunk;
|
|
4931
|
-
if (chunkCount <= 3 || chunkCount % 10 === 0) {
|
|
4932
|
-
log(`chunk #${chunkCount} (${chunk.length} bytes) buffer=${buffer.length} bytes`);
|
|
4933
|
-
}
|
|
4934
|
-
const lines = buffer.split("\n");
|
|
4935
|
-
buffer = lines.pop();
|
|
4936
|
-
for (const line of lines) {
|
|
4937
|
-
if (line.startsWith("data: ")) {
|
|
4938
|
-
const raw = line.slice(6);
|
|
4939
|
-
try {
|
|
4940
|
-
const event = JSON.parse(raw);
|
|
4941
|
-
eventCount++;
|
|
4942
|
-
if (event.id && seenIds.has(event.id)) {
|
|
4943
|
-
log(`skipping duplicate event ${event.id}`);
|
|
4944
|
-
continue;
|
|
4945
|
-
}
|
|
4946
|
-
if (event.id) seenIds.add(event.id);
|
|
4947
|
-
log(`parsed event #${eventCount}: type=${event.event_type}`);
|
|
4948
|
-
yield event;
|
|
4949
|
-
if (event.event_type === "run_complete") {
|
|
4950
|
-
log("run_complete received \u2014 closing stream");
|
|
4951
|
-
gotRunComplete = true;
|
|
4952
|
-
return;
|
|
4953
|
-
}
|
|
4954
|
-
} catch {
|
|
4955
|
-
log(`malformed JSON: ${raw.slice(0, 200)}`);
|
|
4956
|
-
}
|
|
4957
|
-
} else if (line.startsWith(": ")) {
|
|
4958
|
-
if (chunkCount <= 3) {
|
|
4959
|
-
log(`heartbeat: "${line}"`);
|
|
4960
|
-
}
|
|
4961
|
-
}
|
|
4962
|
-
}
|
|
4963
|
-
}
|
|
4964
|
-
} finally {
|
|
4965
|
-
reader.releaseLock();
|
|
4966
|
-
log("reader released");
|
|
4967
|
-
}
|
|
4968
|
-
if (gotRunComplete) return;
|
|
4969
|
-
retries++;
|
|
4970
|
-
if (retries <= MAX_RETRIES) {
|
|
4971
|
-
log(`stream ended without run_complete \u2014 will retry (${retries}/${MAX_RETRIES})`);
|
|
4972
|
-
}
|
|
4973
|
-
}
|
|
4974
|
-
log(`exhausted ${MAX_RETRIES} retries without run_complete`);
|
|
4975
|
-
yield {
|
|
4976
|
-
event_type: "error",
|
|
4977
|
-
message: `Stream lost after ${MAX_RETRIES} reconnect attempts without receiving run_complete`
|
|
4978
|
-
};
|
|
4979
|
-
}
|
|
4980
|
-
|
|
4981
4932
|
// src/lib/run-history.ts
|
|
4982
4933
|
import * as fs2 from "node:fs/promises";
|
|
4983
4934
|
import * as path2 from "node:path";
|
|
@@ -5129,19 +5080,15 @@ function resolveRemotePlatformConfig(config) {
|
|
|
5129
5080
|
// src/commands/run.ts
|
|
5130
5081
|
var isTTY2 = process.stdout.isTTY;
|
|
5131
5082
|
async function runCommand(args) {
|
|
5132
|
-
debug(`start args=${JSON.stringify({ file: args.file, session: args.session })}`);
|
|
5133
5083
|
const accessToken = await loadAccessToken();
|
|
5134
5084
|
if (!accessToken) {
|
|
5135
5085
|
printError("No Vent access token found. Set VENT_ACCESS_TOKEN, run `npx vent-hq login`, or pass --access-token.");
|
|
5136
5086
|
return 2;
|
|
5137
5087
|
}
|
|
5138
|
-
debug(`access-token resolved (${accessToken.slice(0, 8)}\u2026)`);
|
|
5139
5088
|
let config;
|
|
5140
5089
|
try {
|
|
5141
|
-
debug(`reading suite file: ${args.file}`);
|
|
5142
5090
|
const raw = await fs3.readFile(args.file, "utf-8");
|
|
5143
5091
|
const suite = JSON.parse(raw);
|
|
5144
|
-
debug(`suite parsed \u2014 keys: ${Object.keys(suite).join(", ")}`);
|
|
5145
5092
|
if (!suite.connection) {
|
|
5146
5093
|
printError("Suite file must have a `connection` object.");
|
|
5147
5094
|
return 2;
|
|
@@ -5164,7 +5111,6 @@ async function runCommand(args) {
|
|
|
5164
5111
|
printError(`Suite has ${callNames.length} calls. Use --call <name> to pick one: ${callNames.join(", ")}`);
|
|
5165
5112
|
return 2;
|
|
5166
5113
|
}
|
|
5167
|
-
debug(`selected call: ${callName}`);
|
|
5168
5114
|
const call = { ...suite.calls[callName], name: callName };
|
|
5169
5115
|
config = { connection: suite.connection, call };
|
|
5170
5116
|
} catch (err) {
|
|
@@ -5190,7 +5136,6 @@ async function runCommand(args) {
|
|
|
5190
5136
|
);
|
|
5191
5137
|
return 2;
|
|
5192
5138
|
}
|
|
5193
|
-
debug("submitting run to API\u2026");
|
|
5194
5139
|
printInfo("Submitting run\u2026");
|
|
5195
5140
|
let submitResult;
|
|
5196
5141
|
let activeAccessToken = accessToken;
|
|
@@ -5198,12 +5143,8 @@ async function runCommand(args) {
|
|
|
5198
5143
|
async function prepareConfigForSubmit(currentAccessToken) {
|
|
5199
5144
|
if (!configConnection.connection) return;
|
|
5200
5145
|
if (resolvedRemotePlatform) {
|
|
5201
|
-
debug(`ensuring saved ${resolvedRemotePlatform.provider} connection\u2026`);
|
|
5202
5146
|
const ensured = await ensurePlatformConnection(currentAccessToken, resolvedRemotePlatform);
|
|
5203
5147
|
configConnection.connection.platform_connection_id = ensured.platform_connection_id;
|
|
5204
|
-
debug(
|
|
5205
|
-
`saved connection ready id=${ensured.platform_connection_id} created=${ensured.created} updated=${ensured.updated}`
|
|
5206
|
-
);
|
|
5207
5148
|
}
|
|
5208
5149
|
if ("platform" in configConnection.connection) {
|
|
5209
5150
|
delete configConnection.connection.platform;
|
|
@@ -5218,13 +5159,11 @@ async function runCommand(args) {
|
|
|
5218
5159
|
agent_session_id: args.session
|
|
5219
5160
|
})
|
|
5220
5161
|
});
|
|
5221
|
-
debug(`API response status: ${res.status}`);
|
|
5222
5162
|
return res.json();
|
|
5223
5163
|
}
|
|
5224
5164
|
try {
|
|
5225
5165
|
submitResult = await submitPrepared(activeAccessToken);
|
|
5226
5166
|
} catch (err) {
|
|
5227
|
-
debug(`submit error: ${err.message}`);
|
|
5228
5167
|
if (err instanceof ApiError && err.status === 401) {
|
|
5229
5168
|
printError("Access token rejected. Run `npx vent-hq login` to re-authenticate.");
|
|
5230
5169
|
return 1;
|
|
@@ -5234,13 +5173,10 @@ async function runCommand(args) {
|
|
|
5234
5173
|
}
|
|
5235
5174
|
const { run_id } = submitResult;
|
|
5236
5175
|
if (!run_id) {
|
|
5237
|
-
debug(`no run_id in response: ${JSON.stringify(submitResult)}`);
|
|
5238
5176
|
printError("Server returned no run_id. Response: " + JSON.stringify(submitResult));
|
|
5239
5177
|
return 2;
|
|
5240
5178
|
}
|
|
5241
|
-
debug(`run created: ${run_id} status=${submitResult.status}`);
|
|
5242
5179
|
printInfo(`Run ${run_id} created.`);
|
|
5243
|
-
debug(`connecting to SSE stream for run ${run_id}\u2026`);
|
|
5244
5180
|
printInfo(`Streaming results for run ${run_id}\u2026`);
|
|
5245
5181
|
const abortController = new AbortController();
|
|
5246
5182
|
let exitCode = 0;
|
|
@@ -5249,14 +5185,12 @@ async function runCommand(args) {
|
|
|
5249
5185
|
let stopRequested = false;
|
|
5250
5186
|
let stopPromise = null;
|
|
5251
5187
|
const onSignal = () => {
|
|
5252
|
-
debug("received SIGINT/SIGTERM \u2014 requesting cancel and aborting stream");
|
|
5253
5188
|
if (!stopRequested) {
|
|
5254
5189
|
stopRequested = true;
|
|
5255
5190
|
stopPromise = apiFetch(`/runs/${run_id}/stop`, activeAccessToken, {
|
|
5256
5191
|
method: "POST",
|
|
5257
5192
|
signal: AbortSignal.timeout(5e3)
|
|
5258
|
-
}).catch((
|
|
5259
|
-
debug(`stop POST failed: ${err.message}`);
|
|
5193
|
+
}).catch(() => {
|
|
5260
5194
|
});
|
|
5261
5195
|
}
|
|
5262
5196
|
abortController.abort();
|
|
@@ -5264,15 +5198,11 @@ async function runCommand(args) {
|
|
|
5264
5198
|
process.on("SIGINT", onSignal);
|
|
5265
5199
|
process.on("SIGTERM", onSignal);
|
|
5266
5200
|
try {
|
|
5267
|
-
let eventCount = 0;
|
|
5268
5201
|
for await (const event of streamRunEvents(run_id, activeAccessToken, abortController.signal)) {
|
|
5269
|
-
eventCount++;
|
|
5270
5202
|
const meta = event.metadata_json ?? {};
|
|
5271
|
-
debug(`event #${eventCount}: type=${event.event_type} meta_keys=[${Object.keys(meta).join(",")}] message="${event.message ?? ""}"`);
|
|
5272
5203
|
printEvent(event);
|
|
5273
5204
|
if (event.event_type === "call_completed") {
|
|
5274
5205
|
callResults.push(event);
|
|
5275
|
-
debug(`call_completed: name=${meta.call_name} status=${meta.status} duration=${meta.duration_ms}ms completed=${meta.completed}/${meta.total}`);
|
|
5276
5206
|
}
|
|
5277
5207
|
if (event.event_type === "run_complete") {
|
|
5278
5208
|
runCompleteData = meta;
|
|
@@ -5282,35 +5212,28 @@ async function runCommand(args) {
|
|
|
5282
5212
|
return callStatus === "error";
|
|
5283
5213
|
});
|
|
5284
5214
|
exitCode = anyCallErrored ? 1 : 0;
|
|
5285
|
-
debug(`run_complete: anyCallErrored=${anyCallErrored} exitCode=${exitCode}`);
|
|
5286
5215
|
}
|
|
5287
5216
|
if (event.event_type === "error") {
|
|
5288
5217
|
printError(event.message ?? "Stream connection lost");
|
|
5289
5218
|
exitCode = 2;
|
|
5290
5219
|
}
|
|
5291
5220
|
}
|
|
5292
|
-
debug(`SSE stream ended \u2014 received ${eventCount} events total`);
|
|
5293
5221
|
} catch (err) {
|
|
5294
5222
|
if (err.name !== "AbortError") {
|
|
5295
|
-
debug(`stream error: ${err.message}`);
|
|
5296
5223
|
printError(`Stream error: ${err.message}`);
|
|
5297
5224
|
exitCode = 2;
|
|
5298
|
-
} else {
|
|
5299
|
-
debug("stream aborted (user signal)");
|
|
5300
5225
|
}
|
|
5301
5226
|
} finally {
|
|
5302
5227
|
process.off("SIGINT", onSignal);
|
|
5303
5228
|
process.off("SIGTERM", onSignal);
|
|
5304
5229
|
}
|
|
5305
|
-
debug(`summary: callResults=${callResults.length} runComplete=${!!runCompleteData} exitCode=${exitCode}`);
|
|
5306
5230
|
if (runCompleteData) {
|
|
5307
5231
|
let rawRunDetails = null;
|
|
5308
5232
|
if (args.verbose && !isTTY2) {
|
|
5309
5233
|
try {
|
|
5310
5234
|
const res = await apiFetch(`/runs/${run_id}`, activeAccessToken);
|
|
5311
5235
|
rawRunDetails = await res.json();
|
|
5312
|
-
} catch
|
|
5313
|
-
debug(`verbose status fetch failed: ${err.message}`);
|
|
5236
|
+
} catch {
|
|
5314
5237
|
printWarn("Verbose result fetch failed; falling back to streamed summary.");
|
|
5315
5238
|
}
|
|
5316
5239
|
}
|
|
@@ -5330,11 +5253,9 @@ async function runCommand(args) {
|
|
|
5330
5253
|
if (runCompleteData) {
|
|
5331
5254
|
const savedPath = await saveRunHistory(run_id, callResults, runCompleteData);
|
|
5332
5255
|
if (savedPath) {
|
|
5333
|
-
debug(`run saved to ${savedPath}`);
|
|
5334
5256
|
printInfo(`Run saved to ${savedPath}`);
|
|
5335
5257
|
}
|
|
5336
5258
|
}
|
|
5337
|
-
debug(`exiting with code ${exitCode}`);
|
|
5338
5259
|
if (stopPromise) {
|
|
5339
5260
|
await stopPromise;
|
|
5340
5261
|
}
|
|
@@ -5560,10 +5481,6 @@ async function startAgentSession(relayConfig) {
|
|
|
5560
5481
|
healthEndpoint: relayConfig.health_endpoint
|
|
5561
5482
|
};
|
|
5562
5483
|
const client = new RelayClient(clientConfig);
|
|
5563
|
-
client.on("log", (msg) => {
|
|
5564
|
-
if (isVerbose()) process.stdout.write(`${msg}
|
|
5565
|
-
`);
|
|
5566
|
-
});
|
|
5567
5484
|
await client.connect();
|
|
5568
5485
|
let agentProcess = null;
|
|
5569
5486
|
if (relayConfig.start_command) {
|
|
@@ -5573,12 +5490,8 @@ async function startAgentSession(relayConfig) {
|
|
|
5573
5490
|
stdio: "pipe",
|
|
5574
5491
|
env
|
|
5575
5492
|
});
|
|
5576
|
-
agentProcess.stdout?.
|
|
5577
|
-
|
|
5578
|
-
});
|
|
5579
|
-
agentProcess.stderr?.on("data", (data) => {
|
|
5580
|
-
if (isVerbose()) process.stdout.write(`[agent] ${data}`);
|
|
5581
|
-
});
|
|
5493
|
+
agentProcess.stdout?.resume();
|
|
5494
|
+
agentProcess.stderr?.resume();
|
|
5582
5495
|
agentProcess.on("error", (err) => {
|
|
5583
5496
|
process.stdout.write(`Agent process error: ${err.message}
|
|
5584
5497
|
`);
|
|
@@ -5638,7 +5551,6 @@ async function agentStartCommand(args) {
|
|
|
5638
5551
|
}
|
|
5639
5552
|
if (!connection.agent_port) {
|
|
5640
5553
|
connection.agent_port = await findFreePort();
|
|
5641
|
-
debug(`auto-port assigned for agent session: ${connection.agent_port}`);
|
|
5642
5554
|
}
|
|
5643
5555
|
let session = null;
|
|
5644
5556
|
let relay = null;
|
|
@@ -5648,8 +5560,7 @@ async function agentStartCommand(args) {
|
|
|
5648
5560
|
await apiFetch(`/agent-sessions/${session.session_id}/close`, accessToken, {
|
|
5649
5561
|
method: "POST"
|
|
5650
5562
|
});
|
|
5651
|
-
} catch
|
|
5652
|
-
debug(`agent session close failed: ${err.message}`);
|
|
5563
|
+
} catch {
|
|
5653
5564
|
}
|
|
5654
5565
|
};
|
|
5655
5566
|
try {
|
|
@@ -6089,7 +6000,7 @@ async function main() {
|
|
|
6089
6000
|
return 0;
|
|
6090
6001
|
}
|
|
6091
6002
|
if (command === "--version" || command === "-v") {
|
|
6092
|
-
const pkg = await import("./package-
|
|
6003
|
+
const pkg = await import("./package-OH7X3UKK.mjs");
|
|
6093
6004
|
console.log(`vent-hq ${pkg.default.version}`);
|
|
6094
6005
|
return 0;
|
|
6095
6006
|
}
|
|
@@ -4,7 +4,7 @@ import "./chunk-XYDL7GY6.mjs";
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "vent-hq",
|
|
7
|
-
version: "0.13.
|
|
7
|
+
version: "0.13.2",
|
|
8
8
|
type: "module",
|
|
9
9
|
description: "Vent CLI \u2014 CI/CD for voice AI agents",
|
|
10
10
|
bin: {
|
|
@@ -32,15 +32,11 @@ var package_default = {
|
|
|
32
32
|
},
|
|
33
33
|
repository: {
|
|
34
34
|
type: "git",
|
|
35
|
-
url: "https://github.com/vent-hq/
|
|
35
|
+
url: "https://github.com/vent-hq/Vent",
|
|
36
36
|
directory: "packages/cli"
|
|
37
37
|
},
|
|
38
38
|
homepage: "https://venthq.dev",
|
|
39
|
-
dependencies: {
|
|
40
|
-
ws: "^8.18.0"
|
|
41
|
-
},
|
|
42
39
|
devDependencies: {
|
|
43
|
-
"@types/ws": "catalog:",
|
|
44
40
|
"@vent/relay-client": "workspace:*",
|
|
45
41
|
"@vent/shared": "workspace:*",
|
|
46
42
|
esbuild: "catalog:"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vent-hq",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vent CLI — CI/CD for voice AI agents",
|
|
6
6
|
"bin": {
|
|
@@ -23,15 +23,11 @@
|
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
|
-
"url": "https://github.com/vent-hq/
|
|
26
|
+
"url": "https://github.com/vent-hq/Vent",
|
|
27
27
|
"directory": "packages/cli"
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://venthq.dev",
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"ws": "^8.18.0"
|
|
32
|
-
},
|
|
33
30
|
"devDependencies": {
|
|
34
|
-
"@types/ws": "^8.5.0",
|
|
35
31
|
"esbuild": "^0.24.0",
|
|
36
32
|
"@vent/relay-client": "0.1.0",
|
|
37
33
|
"@vent/shared": "0.0.1"
|