@erdoai/cli 0.75.0 → 0.76.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 +122 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -482,6 +482,32 @@ var ErdoClient = class {
|
|
|
482
482
|
getVoiceCall(callID) {
|
|
483
483
|
return this.request("GET", `/v1/voice/calls/${encodeURIComponent(callID)}`);
|
|
484
484
|
}
|
|
485
|
+
// Website concierge widget conversations — the text/voice/video sessions
|
|
486
|
+
// visitors held on the customer's own pages. Covers every widget in the org
|
|
487
|
+
// unless narrowed by the widget handle (its name or public key, vw_...).
|
|
488
|
+
listWidgetConversations(params) {
|
|
489
|
+
const q = new URLSearchParams();
|
|
490
|
+
if (params?.widget) q.set("widget", params.widget);
|
|
491
|
+
if (params?.since) q.set("since", params.since);
|
|
492
|
+
if (params?.until) q.set("until", params.until);
|
|
493
|
+
if (params?.limit !== void 0) q.set("limit", String(params.limit));
|
|
494
|
+
if (params?.offset !== void 0) q.set("offset", String(params.offset));
|
|
495
|
+
if (params?.cursor) q.set("cursor", params.cursor);
|
|
496
|
+
const qs = q.toString();
|
|
497
|
+
return this.request(
|
|
498
|
+
"GET",
|
|
499
|
+
`/v1/voice/widget-conversations${qs ? `?${qs}` : ""}`
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
// The session id identifies the conversation on its own and another org's
|
|
503
|
+
// session is never returned, so the widget handle is optional.
|
|
504
|
+
getWidgetConversation(sessionID, widget) {
|
|
505
|
+
return this.request(
|
|
506
|
+
"POST",
|
|
507
|
+
`/v1/voice/widget-conversations/get`,
|
|
508
|
+
{ session_id: sessionID, ...widget ? { widget } : {} }
|
|
509
|
+
);
|
|
510
|
+
}
|
|
485
511
|
// Run a read-only HogQL query against the org's page-analytics events. Rows are
|
|
486
512
|
// positional per columns; enabled:false means page analytics is off for the org
|
|
487
513
|
// (not zero traffic). A rejected query surfaces PostHog's message as the error.
|
|
@@ -4753,7 +4779,17 @@ sentEmailsCmd.command("get <emailID>").description("Read one sent email, includi
|
|
|
4753
4779
|
fail(e);
|
|
4754
4780
|
}
|
|
4755
4781
|
});
|
|
4756
|
-
var voiceCmd = program.command("voice").description("Read voice agent phone conversations");
|
|
4782
|
+
var voiceCmd = program.command("voice").description("Read voice agent phone calls and website widget conversations");
|
|
4783
|
+
function contactLabel(contact) {
|
|
4784
|
+
if (!contact) return "-";
|
|
4785
|
+
const name = [contact.first_name, contact.last_name].filter(Boolean).join(" ");
|
|
4786
|
+
const reach = contact.email || contact.phone;
|
|
4787
|
+
if (!name && !reach) return "none";
|
|
4788
|
+
return [name, reach].filter(Boolean).join(" \xB7 ");
|
|
4789
|
+
}
|
|
4790
|
+
function leadStatusLabel(outcome) {
|
|
4791
|
+
return outcome ? outcome : "pending";
|
|
4792
|
+
}
|
|
4757
4793
|
var voiceCallsCmd = voiceCmd.command("calls").description("Inbound and outbound phone call records");
|
|
4758
4794
|
voiceCallsCmd.command("list").description("List the organization's phone calls, newest first").option("--agent <slug>", "only calls held by this voice agent, by slug").option("--direction <direction>", "only 'inbound' (calls to the agent's number) or 'outbound'").option("--limit <n>", "page size (default 25, max 100)").option("--offset <n>", "rows to skip").option("--cursor <cursor>", "next_cursor from the preceding page (stable paging)").option("--json", "print the raw JSON result instead of a table").action(
|
|
4759
4795
|
async (opts) => {
|
|
@@ -4775,7 +4811,19 @@ voiceCallsCmd.command("list").description("List the organization's phone calls,
|
|
|
4775
4811
|
return;
|
|
4776
4812
|
}
|
|
4777
4813
|
printAlignedTable(
|
|
4778
|
-
[
|
|
4814
|
+
[
|
|
4815
|
+
"call id",
|
|
4816
|
+
"direction",
|
|
4817
|
+
"from",
|
|
4818
|
+
"to",
|
|
4819
|
+
"status",
|
|
4820
|
+
"secs",
|
|
4821
|
+
"transcript",
|
|
4822
|
+
"contact",
|
|
4823
|
+
"lead",
|
|
4824
|
+
"started",
|
|
4825
|
+
"summary"
|
|
4826
|
+
],
|
|
4779
4827
|
calls.map((call) => [
|
|
4780
4828
|
call.call_id,
|
|
4781
4829
|
call.direction,
|
|
@@ -4784,6 +4832,8 @@ voiceCallsCmd.command("list").description("List the organization's phone calls,
|
|
|
4784
4832
|
call.status,
|
|
4785
4833
|
call.duration_seconds,
|
|
4786
4834
|
call.has_transcript ? "yes" : "no",
|
|
4835
|
+
contactLabel(call.contact),
|
|
4836
|
+
leadStatusLabel(call.lead_status),
|
|
4787
4837
|
call.created_at,
|
|
4788
4838
|
call.transcript_summary
|
|
4789
4839
|
])
|
|
@@ -4799,13 +4849,82 @@ voiceCallsCmd.command("list").description("List the organization's phone calls,
|
|
|
4799
4849
|
}
|
|
4800
4850
|
}
|
|
4801
4851
|
);
|
|
4802
|
-
voiceCallsCmd.command("get <callID>").description(
|
|
4852
|
+
voiceCallsCmd.command("get <callID>").description(
|
|
4853
|
+
"Read one phone call in full: transcript, summary, per-turn LLM metrics, and the lead it produced (contact, lead_status, lead_saved_at)"
|
|
4854
|
+
).action(async (callID) => {
|
|
4803
4855
|
try {
|
|
4804
4856
|
print(await new ErdoClient().getVoiceCall(callID));
|
|
4805
4857
|
} catch (e) {
|
|
4806
4858
|
fail(e);
|
|
4807
4859
|
}
|
|
4808
4860
|
});
|
|
4861
|
+
var widgetConversationsCmd = voiceCmd.command("widget-conversations").description("Website concierge widget conversations (text, voice and video sessions)");
|
|
4862
|
+
widgetConversationsCmd.command("list").description("List the organization's widget conversations, newest first").option("--widget <handle>", "only this widget's conversations \u2014 its name or public key (vw_...)").option("--since <rfc3339>", "only conversations that started at or after this time (inclusive)").option("--until <rfc3339>", "only conversations that started before this time (exclusive)").option("--limit <n>", "page size (default 25, max 100)").option("--offset <n>", "rows to skip").option("--cursor <cursor>", "next_cursor from the preceding page (stable paging)").option("--json", "print the raw JSON result instead of a table").action(
|
|
4863
|
+
async (opts) => {
|
|
4864
|
+
try {
|
|
4865
|
+
const res = await new ErdoClient().listWidgetConversations({
|
|
4866
|
+
widget: opts.widget,
|
|
4867
|
+
since: opts.since,
|
|
4868
|
+
until: opts.until,
|
|
4869
|
+
limit: opts.limit ? Number(opts.limit) : void 0,
|
|
4870
|
+
offset: opts.offset ? Number(opts.offset) : void 0,
|
|
4871
|
+
cursor: opts.cursor
|
|
4872
|
+
});
|
|
4873
|
+
if (opts.json) {
|
|
4874
|
+
print(res);
|
|
4875
|
+
return;
|
|
4876
|
+
}
|
|
4877
|
+
const conversations = res.conversations ?? [];
|
|
4878
|
+
if (conversations.length === 0) {
|
|
4879
|
+
console.log("No conversations match those filters.");
|
|
4880
|
+
return;
|
|
4881
|
+
}
|
|
4882
|
+
printAlignedTable(
|
|
4883
|
+
[
|
|
4884
|
+
"session id",
|
|
4885
|
+
"widget",
|
|
4886
|
+
"modality",
|
|
4887
|
+
"secs",
|
|
4888
|
+
"transcript",
|
|
4889
|
+
"contact",
|
|
4890
|
+
"lead",
|
|
4891
|
+
"started",
|
|
4892
|
+
"summary"
|
|
4893
|
+
],
|
|
4894
|
+
conversations.map((c) => [
|
|
4895
|
+
c.session_id,
|
|
4896
|
+
c.widget_name || c.widget,
|
|
4897
|
+
c.modality,
|
|
4898
|
+
c.duration_seconds,
|
|
4899
|
+
c.has_transcript ? "yes" : "no",
|
|
4900
|
+
contactLabel(c.contact),
|
|
4901
|
+
leadStatusLabel(c.lead_status),
|
|
4902
|
+
c.created_at,
|
|
4903
|
+
c.transcript_summary
|
|
4904
|
+
])
|
|
4905
|
+
);
|
|
4906
|
+
process.stderr.write(
|
|
4907
|
+
`showing ${conversations.length} of ${res.total} conversation(s)
|
|
4908
|
+
`
|
|
4909
|
+
);
|
|
4910
|
+
if (res.next_cursor) {
|
|
4911
|
+
process.stderr.write(`more available \u2014 re-run with --cursor ${res.next_cursor}
|
|
4912
|
+
`);
|
|
4913
|
+
}
|
|
4914
|
+
} catch (e) {
|
|
4915
|
+
fail(e);
|
|
4916
|
+
}
|
|
4917
|
+
}
|
|
4918
|
+
);
|
|
4919
|
+
widgetConversationsCmd.command("get <sessionID>").description(
|
|
4920
|
+
"Read one widget conversation in full: transcript, summary, topics, per-turn LLM metrics, and the lead it produced (contact, lead_status, lead_saved_at)"
|
|
4921
|
+
).option("--widget <handle>", "the widget it belongs to \u2014 optional, the session id identifies it").action(async (sessionID, opts) => {
|
|
4922
|
+
try {
|
|
4923
|
+
print(await new ErdoClient().getWidgetConversation(sessionID, opts.widget));
|
|
4924
|
+
} catch (e) {
|
|
4925
|
+
fail(e);
|
|
4926
|
+
}
|
|
4927
|
+
});
|
|
4809
4928
|
var datasetsCmd = program.command("datasets").description("Datasets");
|
|
4810
4929
|
datasetsCmd.command("list").description("List datasets").option(
|
|
4811
4930
|
"--class <class>",
|