@agenticmail/core 0.9.27 → 0.9.28
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.cjs +71 -11
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +71 -11
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7514,19 +7514,19 @@ var PHONE_MISSION_STATES = [
|
|
|
7514
7514
|
"failed",
|
|
7515
7515
|
"cancelled"
|
|
7516
7516
|
];
|
|
7517
|
-
var PHONE_SERVER_MAX_CALL_DURATION_SECONDS =
|
|
7517
|
+
var PHONE_SERVER_MAX_CALL_DURATION_SECONDS = 7200;
|
|
7518
7518
|
var PHONE_SERVER_MAX_COST_PER_MISSION = 5;
|
|
7519
7519
|
var PHONE_SERVER_MAX_ATTEMPTS = 3;
|
|
7520
7520
|
var PHONE_TASK_MAX_LENGTH = 2e3;
|
|
7521
|
-
var PHONE_SERVER_MAX_EXTENSION_SECONDS_PER_REQUEST =
|
|
7522
|
-
var PHONE_SERVER_MAX_EXTENSION_REQUESTS_PER_CALL =
|
|
7523
|
-
var PHONE_SERVER_MAX_TOTAL_EXTENSION_SECONDS =
|
|
7521
|
+
var PHONE_SERVER_MAX_EXTENSION_SECONDS_PER_REQUEST = 900;
|
|
7522
|
+
var PHONE_SERVER_MAX_EXTENSION_REQUESTS_PER_CALL = 8;
|
|
7523
|
+
var PHONE_SERVER_MAX_TOTAL_EXTENSION_SECONDS = 3600;
|
|
7524
7524
|
var DEFAULT_EXTENSION_POLICY = {
|
|
7525
|
-
maxSecondsPerRequest:
|
|
7526
|
-
// 2 minutes
|
|
7527
|
-
maxRequestsPerCall: 2,
|
|
7528
|
-
maxTotalExtensionSeconds: 300
|
|
7525
|
+
maxSecondsPerRequest: 300,
|
|
7529
7526
|
// 5 minutes
|
|
7527
|
+
maxRequestsPerCall: 4,
|
|
7528
|
+
maxTotalExtensionSeconds: 1200
|
|
7529
|
+
// 20 minutes
|
|
7530
7530
|
};
|
|
7531
7531
|
var PHONE_SERVER_MAX_CALLBACK_CHAIN = 3;
|
|
7532
7532
|
var DEFAULT_CALLBACK_POLICY = {
|
|
@@ -10745,6 +10745,20 @@ var SCHEDULE_CALLBACK_TOOL = {
|
|
|
10745
10745
|
required: ["delay_seconds", "summary_for_next_call"]
|
|
10746
10746
|
}
|
|
10747
10747
|
};
|
|
10748
|
+
var END_CALL_TOOL = {
|
|
10749
|
+
type: "function",
|
|
10750
|
+
name: "end_call",
|
|
10751
|
+
description: `Hang up the call. You MUST call this AFTER you have said goodbye and the conversation is complete \u2014 saying "I'll hang up now" is not enough on its own, the call stays open until you actually call this tool. Use it when: the task is done and you have signed off, the caller has indicated the conversation is over, you have scheduled a callback and said goodbye, or the caller has stopped responding for an extended period. Once called the call drops immediately; you cannot un-hang-up.`,
|
|
10752
|
+
parameters: {
|
|
10753
|
+
type: "object",
|
|
10754
|
+
properties: {
|
|
10755
|
+
reason: {
|
|
10756
|
+
type: "string",
|
|
10757
|
+
description: 'One short line for the audit trail \u2014 e.g. "task complete", "caller said bye", "scheduled callback, signing off". Optional but recommended.'
|
|
10758
|
+
}
|
|
10759
|
+
}
|
|
10760
|
+
}
|
|
10761
|
+
};
|
|
10748
10762
|
var REALTIME_TOOL_DEFINITIONS = {
|
|
10749
10763
|
ask_operator: ASK_OPERATOR_TOOL,
|
|
10750
10764
|
web_search: WEB_SEARCH_TOOL,
|
|
@@ -10755,7 +10769,8 @@ var REALTIME_TOOL_DEFINITIONS = {
|
|
|
10755
10769
|
load_skill: LOAD_SKILL_TOOL,
|
|
10756
10770
|
get_call_status: GET_CALL_STATUS_TOOL,
|
|
10757
10771
|
extend_call_time: EXTEND_CALL_TIME_TOOL,
|
|
10758
|
-
schedule_callback: SCHEDULE_CALLBACK_TOOL
|
|
10772
|
+
schedule_callback: SCHEDULE_CALLBACK_TOOL,
|
|
10773
|
+
end_call: END_CALL_TOOL
|
|
10759
10774
|
};
|
|
10760
10775
|
function buildRealtimeToolGuidance(tools) {
|
|
10761
10776
|
if (tools.length === 0) return "";
|
|
@@ -10802,6 +10817,24 @@ A skill's rendered playbook is now part of your instructions for the rest of the
|
|
|
10802
10817
|
"When in doubt \u2014 out of time, out of extensions, the caller is uncertain \u2014 preferred order is: wrap up gracefully \u2192 schedule_callback \u2192 sign off. Never go silent or invent excuses; the right move is always a clean handoff to a future call."
|
|
10803
10818
|
);
|
|
10804
10819
|
}
|
|
10820
|
+
if (names.has("end_call")) {
|
|
10821
|
+
lines.push(
|
|
10822
|
+
"# Hanging up \u2014 you must call end_call to actually drop the line",
|
|
10823
|
+
`SAYING "I'll hang up now" or "goodbye" does NOT drop the call \u2014 the line stays open until you call the end_call tool. This is the single most important habit on a real phone call: after you have said your goodbye sentence, IMMEDIATELY call end_call({ reason: "..." }). Do not wait for the caller to hang up first; do not assume the system will close the line for you. Call end_call yourself.`,
|
|
10824
|
+
"",
|
|
10825
|
+
"When to call end_call:",
|
|
10826
|
+
"- The task is complete and you have just said goodbye.",
|
|
10827
|
+
'- The caller said "thanks, bye" or otherwise signalled they are done.',
|
|
10828
|
+
`- You scheduled a callback and said "I'll call you back at <when>".`,
|
|
10829
|
+
"- The caller has gone silent for an extended stretch and is clearly not coming back.",
|
|
10830
|
+
"- The operator told you to hang up.",
|
|
10831
|
+
"",
|
|
10832
|
+
"Do NOT call end_call:",
|
|
10833
|
+
"- Mid-conversation when there is still pending business.",
|
|
10834
|
+
"- Because you ran into a tool error \u2014 handle it and keep the call going.",
|
|
10835
|
+
"- During a hold while a tool is running \u2014 let the tool finish."
|
|
10836
|
+
);
|
|
10837
|
+
}
|
|
10805
10838
|
return lines.join("\n");
|
|
10806
10839
|
}
|
|
10807
10840
|
function toolErrorText(err) {
|
|
@@ -11681,8 +11714,10 @@ var RealtimeVoiceBridge = class {
|
|
|
11681
11714
|
}
|
|
11682
11715
|
let granted = Math.min(asked, pol.maxSecondsPerRequest, remainingBudgetSeconds);
|
|
11683
11716
|
const elapsedSeconds = Math.floor((this.nowFn() - this.callStartedAtMs) / 1e3);
|
|
11684
|
-
const
|
|
11685
|
-
|
|
11717
|
+
const hardCeilingRoom = Math.max(
|
|
11718
|
+
0,
|
|
11719
|
+
PHONE_SERVER_MAX_CALL_DURATION_SECONDS - (elapsedSeconds + this.getTimeRemainingSeconds())
|
|
11720
|
+
);
|
|
11686
11721
|
granted = Math.min(granted, hardCeilingRoom);
|
|
11687
11722
|
if (granted <= 0) {
|
|
11688
11723
|
return {
|
|
@@ -11921,6 +11956,31 @@ var RealtimeVoiceBridge = class {
|
|
|
11921
11956
|
return "\u2026\n" + joined.slice(joined.length - MAX_CALLBACK_TRANSCRIPT_DIGEST_LENGTH + 2);
|
|
11922
11957
|
}
|
|
11923
11958
|
// ─── Teardown ─────────────────────────────────────────
|
|
11959
|
+
/**
|
|
11960
|
+
* v0.9.82 — agent-initiated hangup. Called when the `end_call` tool
|
|
11961
|
+
* fires. Logs a marker, then routes through {@link end} so the
|
|
11962
|
+
* carrier sees the bye frame and `onEnd` fires exactly once (the
|
|
11963
|
+
* same teardown path the human-hangup case takes). The "agent-
|
|
11964
|
+
* requested" reason flows through to the mission transcript so a
|
|
11965
|
+
* post-call audit can tell apart "agent hung up" from "human hung
|
|
11966
|
+
* up" from "time budget exceeded".
|
|
11967
|
+
*
|
|
11968
|
+
* Returns the structured result the tool handler echoes back to the
|
|
11969
|
+
* model — even though by the time the model receives it the line
|
|
11970
|
+
* will already be closed, keeping a consistent return shape lets the
|
|
11971
|
+
* executor JSON-stringify deterministically.
|
|
11972
|
+
*/
|
|
11973
|
+
endByAgentRequest(reason) {
|
|
11974
|
+
if (this.ended) {
|
|
11975
|
+
return { ok: false, message: "Call has already ended." };
|
|
11976
|
+
}
|
|
11977
|
+
const trimmed = (reason ?? "").trim();
|
|
11978
|
+
this.emitTranscript("system", `Agent requested hangup. Reason: ${trimmed || "unspecified"}`, {
|
|
11979
|
+
endedByAgent: true
|
|
11980
|
+
});
|
|
11981
|
+
this.end("agent-requested");
|
|
11982
|
+
return { ok: true, message: "Call ended." };
|
|
11983
|
+
}
|
|
11924
11984
|
/**
|
|
11925
11985
|
* End the bridge. Idempotent — the first call wins, later calls are
|
|
11926
11986
|
* no-ops. Sends the carrier's end-of-call frame (if it has one — 46elks
|
package/dist/index.d.cts
CHANGED
|
@@ -2618,7 +2618,7 @@ type PhoneNumberRisk = 'invalid' | 'standard' | 'premium_or_special';
|
|
|
2618
2618
|
* be MORE restrictive than the server, never less. A phone mission places
|
|
2619
2619
|
* real, billed calls — these bounds are the financial blast-radius cap.
|
|
2620
2620
|
*/
|
|
2621
|
-
declare const PHONE_SERVER_MAX_CALL_DURATION_SECONDS =
|
|
2621
|
+
declare const PHONE_SERVER_MAX_CALL_DURATION_SECONDS = 7200;
|
|
2622
2622
|
declare const PHONE_SERVER_MAX_COST_PER_MISSION = 5;
|
|
2623
2623
|
declare const PHONE_SERVER_MAX_ATTEMPTS = 3;
|
|
2624
2624
|
/** Hard cap on the free-text `task` fed to the voice runtime. */
|
|
@@ -3692,6 +3692,24 @@ declare class RealtimeVoiceBridge {
|
|
|
3692
3692
|
* Always honours {@link MAX_CALLBACK_TRANSCRIPT_DIGEST_LENGTH}.
|
|
3693
3693
|
*/
|
|
3694
3694
|
private composeTranscriptDigest;
|
|
3695
|
+
/**
|
|
3696
|
+
* v0.9.82 — agent-initiated hangup. Called when the `end_call` tool
|
|
3697
|
+
* fires. Logs a marker, then routes through {@link end} so the
|
|
3698
|
+
* carrier sees the bye frame and `onEnd` fires exactly once (the
|
|
3699
|
+
* same teardown path the human-hangup case takes). The "agent-
|
|
3700
|
+
* requested" reason flows through to the mission transcript so a
|
|
3701
|
+
* post-call audit can tell apart "agent hung up" from "human hung
|
|
3702
|
+
* up" from "time budget exceeded".
|
|
3703
|
+
*
|
|
3704
|
+
* Returns the structured result the tool handler echoes back to the
|
|
3705
|
+
* model — even though by the time the model receives it the line
|
|
3706
|
+
* will already be closed, keeping a consistent return shape lets the
|
|
3707
|
+
* executor JSON-stringify deterministically.
|
|
3708
|
+
*/
|
|
3709
|
+
endByAgentRequest(reason?: string): {
|
|
3710
|
+
ok: boolean;
|
|
3711
|
+
message: string;
|
|
3712
|
+
};
|
|
3695
3713
|
/**
|
|
3696
3714
|
* End the bridge. Idempotent — the first call wins, later calls are
|
|
3697
3715
|
* no-ops. Sends the carrier's end-of-call frame (if it has one — 46elks
|
package/dist/index.d.ts
CHANGED
|
@@ -2618,7 +2618,7 @@ type PhoneNumberRisk = 'invalid' | 'standard' | 'premium_or_special';
|
|
|
2618
2618
|
* be MORE restrictive than the server, never less. A phone mission places
|
|
2619
2619
|
* real, billed calls — these bounds are the financial blast-radius cap.
|
|
2620
2620
|
*/
|
|
2621
|
-
declare const PHONE_SERVER_MAX_CALL_DURATION_SECONDS =
|
|
2621
|
+
declare const PHONE_SERVER_MAX_CALL_DURATION_SECONDS = 7200;
|
|
2622
2622
|
declare const PHONE_SERVER_MAX_COST_PER_MISSION = 5;
|
|
2623
2623
|
declare const PHONE_SERVER_MAX_ATTEMPTS = 3;
|
|
2624
2624
|
/** Hard cap on the free-text `task` fed to the voice runtime. */
|
|
@@ -3692,6 +3692,24 @@ declare class RealtimeVoiceBridge {
|
|
|
3692
3692
|
* Always honours {@link MAX_CALLBACK_TRANSCRIPT_DIGEST_LENGTH}.
|
|
3693
3693
|
*/
|
|
3694
3694
|
private composeTranscriptDigest;
|
|
3695
|
+
/**
|
|
3696
|
+
* v0.9.82 — agent-initiated hangup. Called when the `end_call` tool
|
|
3697
|
+
* fires. Logs a marker, then routes through {@link end} so the
|
|
3698
|
+
* carrier sees the bye frame and `onEnd` fires exactly once (the
|
|
3699
|
+
* same teardown path the human-hangup case takes). The "agent-
|
|
3700
|
+
* requested" reason flows through to the mission transcript so a
|
|
3701
|
+
* post-call audit can tell apart "agent hung up" from "human hung
|
|
3702
|
+
* up" from "time budget exceeded".
|
|
3703
|
+
*
|
|
3704
|
+
* Returns the structured result the tool handler echoes back to the
|
|
3705
|
+
* model — even though by the time the model receives it the line
|
|
3706
|
+
* will already be closed, keeping a consistent return shape lets the
|
|
3707
|
+
* executor JSON-stringify deterministically.
|
|
3708
|
+
*/
|
|
3709
|
+
endByAgentRequest(reason?: string): {
|
|
3710
|
+
ok: boolean;
|
|
3711
|
+
message: string;
|
|
3712
|
+
};
|
|
3695
3713
|
/**
|
|
3696
3714
|
* End the bridge. Idempotent — the first call wins, later calls are
|
|
3697
3715
|
* no-ops. Sends the carrier's end-of-call frame (if it has one — 46elks
|
package/dist/index.js
CHANGED
|
@@ -5865,19 +5865,19 @@ var PHONE_MISSION_STATES = [
|
|
|
5865
5865
|
"failed",
|
|
5866
5866
|
"cancelled"
|
|
5867
5867
|
];
|
|
5868
|
-
var PHONE_SERVER_MAX_CALL_DURATION_SECONDS =
|
|
5868
|
+
var PHONE_SERVER_MAX_CALL_DURATION_SECONDS = 7200;
|
|
5869
5869
|
var PHONE_SERVER_MAX_COST_PER_MISSION = 5;
|
|
5870
5870
|
var PHONE_SERVER_MAX_ATTEMPTS = 3;
|
|
5871
5871
|
var PHONE_TASK_MAX_LENGTH = 2e3;
|
|
5872
|
-
var PHONE_SERVER_MAX_EXTENSION_SECONDS_PER_REQUEST =
|
|
5873
|
-
var PHONE_SERVER_MAX_EXTENSION_REQUESTS_PER_CALL =
|
|
5874
|
-
var PHONE_SERVER_MAX_TOTAL_EXTENSION_SECONDS =
|
|
5872
|
+
var PHONE_SERVER_MAX_EXTENSION_SECONDS_PER_REQUEST = 900;
|
|
5873
|
+
var PHONE_SERVER_MAX_EXTENSION_REQUESTS_PER_CALL = 8;
|
|
5874
|
+
var PHONE_SERVER_MAX_TOTAL_EXTENSION_SECONDS = 3600;
|
|
5875
5875
|
var DEFAULT_EXTENSION_POLICY = {
|
|
5876
|
-
maxSecondsPerRequest:
|
|
5877
|
-
// 2 minutes
|
|
5878
|
-
maxRequestsPerCall: 2,
|
|
5879
|
-
maxTotalExtensionSeconds: 300
|
|
5876
|
+
maxSecondsPerRequest: 300,
|
|
5880
5877
|
// 5 minutes
|
|
5878
|
+
maxRequestsPerCall: 4,
|
|
5879
|
+
maxTotalExtensionSeconds: 1200
|
|
5880
|
+
// 20 minutes
|
|
5881
5881
|
};
|
|
5882
5882
|
var PHONE_SERVER_MAX_CALLBACK_CHAIN = 3;
|
|
5883
5883
|
var DEFAULT_CALLBACK_POLICY = {
|
|
@@ -9096,6 +9096,20 @@ var SCHEDULE_CALLBACK_TOOL = {
|
|
|
9096
9096
|
required: ["delay_seconds", "summary_for_next_call"]
|
|
9097
9097
|
}
|
|
9098
9098
|
};
|
|
9099
|
+
var END_CALL_TOOL = {
|
|
9100
|
+
type: "function",
|
|
9101
|
+
name: "end_call",
|
|
9102
|
+
description: `Hang up the call. You MUST call this AFTER you have said goodbye and the conversation is complete \u2014 saying "I'll hang up now" is not enough on its own, the call stays open until you actually call this tool. Use it when: the task is done and you have signed off, the caller has indicated the conversation is over, you have scheduled a callback and said goodbye, or the caller has stopped responding for an extended period. Once called the call drops immediately; you cannot un-hang-up.`,
|
|
9103
|
+
parameters: {
|
|
9104
|
+
type: "object",
|
|
9105
|
+
properties: {
|
|
9106
|
+
reason: {
|
|
9107
|
+
type: "string",
|
|
9108
|
+
description: 'One short line for the audit trail \u2014 e.g. "task complete", "caller said bye", "scheduled callback, signing off". Optional but recommended.'
|
|
9109
|
+
}
|
|
9110
|
+
}
|
|
9111
|
+
}
|
|
9112
|
+
};
|
|
9099
9113
|
var REALTIME_TOOL_DEFINITIONS = {
|
|
9100
9114
|
ask_operator: ASK_OPERATOR_TOOL,
|
|
9101
9115
|
web_search: WEB_SEARCH_TOOL,
|
|
@@ -9106,7 +9120,8 @@ var REALTIME_TOOL_DEFINITIONS = {
|
|
|
9106
9120
|
load_skill: LOAD_SKILL_TOOL,
|
|
9107
9121
|
get_call_status: GET_CALL_STATUS_TOOL,
|
|
9108
9122
|
extend_call_time: EXTEND_CALL_TIME_TOOL,
|
|
9109
|
-
schedule_callback: SCHEDULE_CALLBACK_TOOL
|
|
9123
|
+
schedule_callback: SCHEDULE_CALLBACK_TOOL,
|
|
9124
|
+
end_call: END_CALL_TOOL
|
|
9110
9125
|
};
|
|
9111
9126
|
function buildRealtimeToolGuidance(tools) {
|
|
9112
9127
|
if (tools.length === 0) return "";
|
|
@@ -9153,6 +9168,24 @@ A skill's rendered playbook is now part of your instructions for the rest of the
|
|
|
9153
9168
|
"When in doubt \u2014 out of time, out of extensions, the caller is uncertain \u2014 preferred order is: wrap up gracefully \u2192 schedule_callback \u2192 sign off. Never go silent or invent excuses; the right move is always a clean handoff to a future call."
|
|
9154
9169
|
);
|
|
9155
9170
|
}
|
|
9171
|
+
if (names.has("end_call")) {
|
|
9172
|
+
lines.push(
|
|
9173
|
+
"# Hanging up \u2014 you must call end_call to actually drop the line",
|
|
9174
|
+
`SAYING "I'll hang up now" or "goodbye" does NOT drop the call \u2014 the line stays open until you call the end_call tool. This is the single most important habit on a real phone call: after you have said your goodbye sentence, IMMEDIATELY call end_call({ reason: "..." }). Do not wait for the caller to hang up first; do not assume the system will close the line for you. Call end_call yourself.`,
|
|
9175
|
+
"",
|
|
9176
|
+
"When to call end_call:",
|
|
9177
|
+
"- The task is complete and you have just said goodbye.",
|
|
9178
|
+
'- The caller said "thanks, bye" or otherwise signalled they are done.',
|
|
9179
|
+
`- You scheduled a callback and said "I'll call you back at <when>".`,
|
|
9180
|
+
"- The caller has gone silent for an extended stretch and is clearly not coming back.",
|
|
9181
|
+
"- The operator told you to hang up.",
|
|
9182
|
+
"",
|
|
9183
|
+
"Do NOT call end_call:",
|
|
9184
|
+
"- Mid-conversation when there is still pending business.",
|
|
9185
|
+
"- Because you ran into a tool error \u2014 handle it and keep the call going.",
|
|
9186
|
+
"- During a hold while a tool is running \u2014 let the tool finish."
|
|
9187
|
+
);
|
|
9188
|
+
}
|
|
9156
9189
|
return lines.join("\n");
|
|
9157
9190
|
}
|
|
9158
9191
|
function toolErrorText(err) {
|
|
@@ -10032,8 +10065,10 @@ var RealtimeVoiceBridge = class {
|
|
|
10032
10065
|
}
|
|
10033
10066
|
let granted = Math.min(asked, pol.maxSecondsPerRequest, remainingBudgetSeconds);
|
|
10034
10067
|
const elapsedSeconds = Math.floor((this.nowFn() - this.callStartedAtMs) / 1e3);
|
|
10035
|
-
const
|
|
10036
|
-
|
|
10068
|
+
const hardCeilingRoom = Math.max(
|
|
10069
|
+
0,
|
|
10070
|
+
PHONE_SERVER_MAX_CALL_DURATION_SECONDS - (elapsedSeconds + this.getTimeRemainingSeconds())
|
|
10071
|
+
);
|
|
10037
10072
|
granted = Math.min(granted, hardCeilingRoom);
|
|
10038
10073
|
if (granted <= 0) {
|
|
10039
10074
|
return {
|
|
@@ -10272,6 +10307,31 @@ var RealtimeVoiceBridge = class {
|
|
|
10272
10307
|
return "\u2026\n" + joined.slice(joined.length - MAX_CALLBACK_TRANSCRIPT_DIGEST_LENGTH + 2);
|
|
10273
10308
|
}
|
|
10274
10309
|
// ─── Teardown ─────────────────────────────────────────
|
|
10310
|
+
/**
|
|
10311
|
+
* v0.9.82 — agent-initiated hangup. Called when the `end_call` tool
|
|
10312
|
+
* fires. Logs a marker, then routes through {@link end} so the
|
|
10313
|
+
* carrier sees the bye frame and `onEnd` fires exactly once (the
|
|
10314
|
+
* same teardown path the human-hangup case takes). The "agent-
|
|
10315
|
+
* requested" reason flows through to the mission transcript so a
|
|
10316
|
+
* post-call audit can tell apart "agent hung up" from "human hung
|
|
10317
|
+
* up" from "time budget exceeded".
|
|
10318
|
+
*
|
|
10319
|
+
* Returns the structured result the tool handler echoes back to the
|
|
10320
|
+
* model — even though by the time the model receives it the line
|
|
10321
|
+
* will already be closed, keeping a consistent return shape lets the
|
|
10322
|
+
* executor JSON-stringify deterministically.
|
|
10323
|
+
*/
|
|
10324
|
+
endByAgentRequest(reason) {
|
|
10325
|
+
if (this.ended) {
|
|
10326
|
+
return { ok: false, message: "Call has already ended." };
|
|
10327
|
+
}
|
|
10328
|
+
const trimmed = (reason ?? "").trim();
|
|
10329
|
+
this.emitTranscript("system", `Agent requested hangup. Reason: ${trimmed || "unspecified"}`, {
|
|
10330
|
+
endedByAgent: true
|
|
10331
|
+
});
|
|
10332
|
+
this.end("agent-requested");
|
|
10333
|
+
return { ok: true, message: "Call ended." };
|
|
10334
|
+
}
|
|
10275
10335
|
/**
|
|
10276
10336
|
* End the bridge. Idempotent — the first call wins, later calls are
|
|
10277
10337
|
* no-ops. Sends the carrier's end-of-call frame (if it has one — 46elks
|