eve-lark 0.4.3 → 0.4.5
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 +210 -53
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -610,10 +610,29 @@ function buildStreamingCard(opts) {
|
|
|
610
610
|
lines.push(`<font color='grey'>${opts.status}</font>`);
|
|
611
611
|
}
|
|
612
612
|
lines.push(opts.buffer.length > 0 ? opts.buffer : "_\u2026_");
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
613
|
+
if (opts.askRequest) {
|
|
614
|
+
lines.push(`**${opts.askRequest.prompt}**`);
|
|
615
|
+
if (opts.askRequest.allowFreeform && (opts.askRequest.options?.length ?? 0) === 0) {
|
|
616
|
+
lines.push(`<font color='grey'>_Reply to this chat with your answer_</font>`);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
const elements = [
|
|
620
|
+
{ tag: "div", text: { tag: "lark_md", content: lines.join("\n\n") } }
|
|
621
|
+
];
|
|
622
|
+
if (opts.askRequest?.options && opts.askRequest.options.length > 0) {
|
|
623
|
+
const buttons = opts.askRequest.options.map((opt) => ({
|
|
624
|
+
tag: "button",
|
|
625
|
+
text: { tag: "plain_text", content: opt.label },
|
|
626
|
+
type: opt.style ?? "default",
|
|
627
|
+
value: {
|
|
628
|
+
[ASK_BUTTON_VALUE_MARKER]: true,
|
|
629
|
+
requestId: opts.askRequest.requestId,
|
|
630
|
+
optionId: opt.id
|
|
631
|
+
}
|
|
632
|
+
}));
|
|
633
|
+
elements.push({ tag: "action", actions: buttons });
|
|
634
|
+
}
|
|
635
|
+
return { config: { ...BASE_CONFIG }, elements };
|
|
617
636
|
}
|
|
618
637
|
__name(buildStreamingCard, "buildStreamingCard");
|
|
619
638
|
function buildErrorCard(message) {
|
|
@@ -681,10 +700,12 @@ function buildAskCard(request) {
|
|
|
681
700
|
return { config: { ...BASE_CONFIG }, elements };
|
|
682
701
|
}
|
|
683
702
|
__name(buildAskCard, "buildAskCard");
|
|
684
|
-
function buildAskAnsweredCard(request, selected) {
|
|
685
|
-
const elements = [
|
|
686
|
-
|
|
687
|
-
|
|
703
|
+
function buildAskAnsweredCard(request, selected, priorBuffer) {
|
|
704
|
+
const elements = [];
|
|
705
|
+
if (priorBuffer && priorBuffer.length > 0) {
|
|
706
|
+
elements.push({ tag: "div", text: { tag: "lark_md", content: priorBuffer } });
|
|
707
|
+
}
|
|
708
|
+
elements.push({ tag: "div", text: { tag: "lark_md", content: request.prompt } });
|
|
688
709
|
const summary = selected.kind === "option" ? `<font color='green'>\u2713 ${escapeMarkdown(selected.label)}</font>` : `<font color='green'>\u2713 ${escapeMarkdown(selected.text)}</font>`;
|
|
689
710
|
elements.push({ tag: "div", text: { tag: "lark_md", content: summary } });
|
|
690
711
|
return { config: { ...BASE_CONFIG }, elements };
|
|
@@ -702,6 +723,28 @@ function buildCardKitStreamingCard(opts) {
|
|
|
702
723
|
lines.push(`<font color='grey'>${opts.status}</font>`);
|
|
703
724
|
}
|
|
704
725
|
lines.push(opts.buffer.length > 0 ? opts.buffer : "_\u2026_");
|
|
726
|
+
if (opts.askRequest) {
|
|
727
|
+
lines.push(`**${opts.askRequest.prompt}**`);
|
|
728
|
+
if (opts.askRequest.allowFreeform && (opts.askRequest.options?.length ?? 0) === 0) {
|
|
729
|
+
lines.push(`<font color='grey'>_Reply to this chat with your answer_</font>`);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
const elements = [
|
|
733
|
+
{ tag: "markdown", content: lines.join("\n\n") }
|
|
734
|
+
];
|
|
735
|
+
if (opts.askRequest?.options && opts.askRequest.options.length > 0) {
|
|
736
|
+
const buttons = opts.askRequest.options.map((opt) => ({
|
|
737
|
+
tag: "button",
|
|
738
|
+
text: { tag: "plain_text", content: opt.label },
|
|
739
|
+
type: opt.style ?? "default",
|
|
740
|
+
value: {
|
|
741
|
+
[ASK_BUTTON_VALUE_MARKER]: true,
|
|
742
|
+
requestId: opts.askRequest.requestId,
|
|
743
|
+
optionId: opt.id
|
|
744
|
+
}
|
|
745
|
+
}));
|
|
746
|
+
elements.push({ tag: "action", actions: buttons });
|
|
747
|
+
}
|
|
705
748
|
return {
|
|
706
749
|
schema: "2.0",
|
|
707
750
|
config: {
|
|
@@ -709,27 +752,38 @@ function buildCardKitStreamingCard(opts) {
|
|
|
709
752
|
wide_screen_mode: true,
|
|
710
753
|
update_multi: true
|
|
711
754
|
},
|
|
712
|
-
body: {
|
|
713
|
-
elements: [
|
|
714
|
-
{ tag: "markdown", content: lines.join("\n\n") }
|
|
715
|
-
]
|
|
716
|
-
}
|
|
755
|
+
body: { elements }
|
|
717
756
|
};
|
|
718
757
|
}
|
|
719
758
|
__name(buildCardKitStreamingCard, "buildCardKitStreamingCard");
|
|
720
|
-
function buildCardKitFinalCard(text, toolCalls) {
|
|
759
|
+
function buildCardKitFinalCard(text, toolCalls, askRequest) {
|
|
721
760
|
const lines = [];
|
|
722
761
|
const toolLine = renderToolCalls(toolCalls ?? []);
|
|
723
762
|
if (toolLine) lines.push(toolLine);
|
|
724
763
|
lines.push(text);
|
|
764
|
+
if (askRequest) {
|
|
765
|
+
lines.push(`**${askRequest.prompt}**`);
|
|
766
|
+
}
|
|
767
|
+
const elements = [
|
|
768
|
+
{ tag: "markdown", content: lines.join("\n\n") }
|
|
769
|
+
];
|
|
770
|
+
if (askRequest?.options && askRequest.options.length > 0) {
|
|
771
|
+
const buttons = askRequest.options.map((opt) => ({
|
|
772
|
+
tag: "button",
|
|
773
|
+
text: { tag: "plain_text", content: opt.label },
|
|
774
|
+
type: opt.style ?? "default",
|
|
775
|
+
value: {
|
|
776
|
+
[ASK_BUTTON_VALUE_MARKER]: true,
|
|
777
|
+
requestId: askRequest.requestId,
|
|
778
|
+
optionId: opt.id
|
|
779
|
+
}
|
|
780
|
+
}));
|
|
781
|
+
elements.push({ tag: "action", actions: buttons });
|
|
782
|
+
}
|
|
725
783
|
return {
|
|
726
784
|
schema: "2.0",
|
|
727
785
|
config: { streaming_mode: false, wide_screen_mode: true, update_multi: true },
|
|
728
|
-
body: {
|
|
729
|
-
elements: [
|
|
730
|
-
{ tag: "markdown", content: lines.join("\n\n") }
|
|
731
|
-
]
|
|
732
|
-
}
|
|
786
|
+
body: { elements }
|
|
733
787
|
};
|
|
734
788
|
}
|
|
735
789
|
__name(buildCardKitFinalCard, "buildCardKitFinalCard");
|
|
@@ -746,6 +800,10 @@ var StreamingCardController = class {
|
|
|
746
800
|
status;
|
|
747
801
|
messageId;
|
|
748
802
|
fallbackToText = false;
|
|
803
|
+
/** Active HITL input request, when set via `setAskRequest`. The card
|
|
804
|
+
* builder appends prompt + buttons to the same streaming card so the
|
|
805
|
+
* user can answer inline instead of getting a separate ask-card. */
|
|
806
|
+
askRequest = null;
|
|
749
807
|
/** Tool calls made during this turn, in order. Rendered above the buffer
|
|
750
808
|
* so users can see what the agent is doing / has done, Claude-Code-style. */
|
|
751
809
|
toolCalls = [];
|
|
@@ -817,6 +875,82 @@ var StreamingCardController = class {
|
|
|
817
875
|
getToolCalls() {
|
|
818
876
|
return this.toolCalls;
|
|
819
877
|
}
|
|
878
|
+
/** Current streaming buffer (for handleCardAction to preserve when patching
|
|
879
|
+
* the "answered" state of an inline ask card). */
|
|
880
|
+
getBuffer() {
|
|
881
|
+
return this.buffer;
|
|
882
|
+
}
|
|
883
|
+
/** Card message id (so input.requested can reuse the existing card instead
|
|
884
|
+
* of creating a separate ask-card). */
|
|
885
|
+
getMessageId() {
|
|
886
|
+
return this.messageId;
|
|
887
|
+
}
|
|
888
|
+
/** Active HITL request being rendered inline on this card, or null. */
|
|
889
|
+
getAskRequest() {
|
|
890
|
+
return this.askRequest;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Render an `ask_question` request inline on this card by appending prompt
|
|
894
|
+
* + option buttons below the streaming text. Patches immediately so the
|
|
895
|
+
* user sees the buttons as soon as the agent asks.
|
|
896
|
+
*
|
|
897
|
+
* If the prior turn already finalized (state="completed"), transition back
|
|
898
|
+
* to "streaming" so the next patch can update the same card. The card
|
|
899
|
+
* keeps its messageId — no new card is sent.
|
|
900
|
+
*/
|
|
901
|
+
setAskRequest(req) {
|
|
902
|
+
if (this.state === "aborted") return;
|
|
903
|
+
this.askRequest = req;
|
|
904
|
+
if (this.state === "completed" && this.messageId) {
|
|
905
|
+
this.state = "streaming";
|
|
906
|
+
}
|
|
907
|
+
if (this.state === "streaming") {
|
|
908
|
+
this.schedulePatch();
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
/** Clear the inline ask request (e.g. after the user clicked an option). */
|
|
912
|
+
clearAskRequest() {
|
|
913
|
+
this.askRequest = null;
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Reset per-turn state for the next turn within the same session. Clears
|
|
917
|
+
* the streaming buffer, tool-call history, status, and any inline ask —
|
|
918
|
+
* but keeps the card messageId and transitions back to "streaming" so the
|
|
919
|
+
* next message.appended patches the SAME card. Without this, the second
|
|
920
|
+
* turn's message.completed would create a brand-new card and the user
|
|
921
|
+
* would see N cards for N turns within one logical conversation.
|
|
922
|
+
*
|
|
923
|
+
* Called from the channel's `turn.started` event handler.
|
|
924
|
+
*/
|
|
925
|
+
resetForNewTurn() {
|
|
926
|
+
this.buffer = "";
|
|
927
|
+
this.status = void 0;
|
|
928
|
+
this.toolCalls = [];
|
|
929
|
+
this.askRequest = null;
|
|
930
|
+
this.fallbackToText = false;
|
|
931
|
+
this.cancelCreateTimer();
|
|
932
|
+
this.cancelPatchTimer();
|
|
933
|
+
this.patchInFlight = null;
|
|
934
|
+
this.patchScheduled = false;
|
|
935
|
+
if (this.messageId) {
|
|
936
|
+
this.state = "streaming";
|
|
937
|
+
} else {
|
|
938
|
+
this.state = "idle";
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* Full reset for a brand-new inbound user message (not a continuation
|
|
943
|
+
* of the same conversation flow). Same as {@link resetForNewTurn} but
|
|
944
|
+
* ALSO clears the card messageId so the next `sendCard` creates a fresh
|
|
945
|
+
* card. Without this, all top-level messages in the same chat would
|
|
946
|
+
* patch the first card — the user would only see the latest reply
|
|
947
|
+
* overwritten onto one card instead of N independent cards.
|
|
948
|
+
*/
|
|
949
|
+
resetForNewMessage() {
|
|
950
|
+
this.resetForNewTurn();
|
|
951
|
+
this.messageId = void 0;
|
|
952
|
+
this.state = "idle";
|
|
953
|
+
}
|
|
820
954
|
async finalize(fullText) {
|
|
821
955
|
if (this.state === "completed" || this.state === "aborted") return;
|
|
822
956
|
this.cancelCreateTimer();
|
|
@@ -836,7 +970,7 @@ var StreamingCardController = class {
|
|
|
836
970
|
try {
|
|
837
971
|
const res = await this.client.sendCard({
|
|
838
972
|
chatId: this.deps.chatId,
|
|
839
|
-
card: this.deps.useCardKitV2 ? buildCardKitFinalCard(fullText, this.toolCalls) : buildTextCard(fullText),
|
|
973
|
+
card: this.deps.useCardKitV2 ? buildCardKitFinalCard(fullText, this.toolCalls, this.askRequest) : buildTextCard(fullText),
|
|
840
974
|
rootId: this.deps.rootId,
|
|
841
975
|
parentId: this.deps.parentId
|
|
842
976
|
});
|
|
@@ -862,7 +996,7 @@ var StreamingCardController = class {
|
|
|
862
996
|
}
|
|
863
997
|
await this.client.patchCard({
|
|
864
998
|
messageId: this.messageId,
|
|
865
|
-
card: this.deps.useCardKitV2 ? buildCardKitStreamingCard({ buffer: fullText, streamingMode: false, toolCalls: this.toolCalls }) : buildStreamingCard({ buffer: fullText, status: void 0, toolCalls: this.toolCalls })
|
|
999
|
+
card: this.deps.useCardKitV2 ? buildCardKitStreamingCard({ buffer: fullText, streamingMode: false, toolCalls: this.toolCalls, askRequest: this.askRequest }) : buildStreamingCard({ buffer: fullText, status: void 0, toolCalls: this.toolCalls, askRequest: this.askRequest })
|
|
866
1000
|
});
|
|
867
1001
|
this.state = "completed";
|
|
868
1002
|
}
|
|
@@ -914,7 +1048,7 @@ var StreamingCardController = class {
|
|
|
914
1048
|
try {
|
|
915
1049
|
const res = await this.client.sendCard({
|
|
916
1050
|
chatId: this.deps.chatId,
|
|
917
|
-
card: this.deps.useCardKitV2 ? buildCardKitStreamingCard({ buffer: this.buffer, status: this.status, streamingMode: true, toolCalls: this.toolCalls }) : buildStreamingCard({ buffer: this.buffer, status: this.status, toolCalls: this.toolCalls }),
|
|
1051
|
+
card: this.deps.useCardKitV2 ? buildCardKitStreamingCard({ buffer: this.buffer, status: this.status, streamingMode: true, toolCalls: this.toolCalls, askRequest: this.askRequest }) : buildStreamingCard({ buffer: this.buffer, status: this.status, toolCalls: this.toolCalls, askRequest: this.askRequest }),
|
|
918
1052
|
rootId: this.deps.rootId,
|
|
919
1053
|
parentId: this.deps.parentId
|
|
920
1054
|
});
|
|
@@ -952,7 +1086,7 @@ var StreamingCardController = class {
|
|
|
952
1086
|
if (this.state !== "streaming") return;
|
|
953
1087
|
if (this.patchInFlight) return;
|
|
954
1088
|
if (this.messageId === void 0) return;
|
|
955
|
-
const card = this.deps.useCardKitV2 ? buildCardKitStreamingCard({ buffer: this.buffer, status: this.status, streamingMode: true, toolCalls: this.toolCalls }) : buildStreamingCard({ buffer: this.buffer, status: this.status, toolCalls: this.toolCalls });
|
|
1089
|
+
const card = this.deps.useCardKitV2 ? buildCardKitStreamingCard({ buffer: this.buffer, status: this.status, streamingMode: true, toolCalls: this.toolCalls, askRequest: this.askRequest }) : buildStreamingCard({ buffer: this.buffer, status: this.status, toolCalls: this.toolCalls, askRequest: this.askRequest });
|
|
956
1090
|
this.patchInFlight = this.client.patchCard({ messageId: this.messageId, card }).catch((e) => {
|
|
957
1091
|
console.warn(
|
|
958
1092
|
"[eve-lark] streaming card patch failed:",
|
|
@@ -1582,6 +1716,7 @@ function createLarkChannel(optionsInput) {
|
|
|
1582
1716
|
const pendingInputsByRequestId = /* @__PURE__ */ new Map();
|
|
1583
1717
|
const pendingInputsByChatToken = /* @__PURE__ */ new Map();
|
|
1584
1718
|
const authCards = /* @__PURE__ */ new Map();
|
|
1719
|
+
const expectFreshCard = /* @__PURE__ */ new Set();
|
|
1585
1720
|
function getController(sessionId, meta) {
|
|
1586
1721
|
let ctrl = controllers.get(sessionId);
|
|
1587
1722
|
if (!ctrl) {
|
|
@@ -1609,11 +1744,6 @@ function createLarkChannel(optionsInput) {
|
|
|
1609
1744
|
return ctrl;
|
|
1610
1745
|
}
|
|
1611
1746
|
__name(getController, "getController");
|
|
1612
|
-
function dropController(sessionId) {
|
|
1613
|
-
controllers.delete(sessionId);
|
|
1614
|
-
sessionMeta.delete(sessionId);
|
|
1615
|
-
}
|
|
1616
|
-
__name(dropController, "dropController");
|
|
1617
1747
|
async function cleanupAckReaction(sessionId) {
|
|
1618
1748
|
const meta = sessionMeta.get(sessionId);
|
|
1619
1749
|
if (!meta?.ackReactionId || !meta.messageId) return;
|
|
@@ -1940,6 +2070,7 @@ function createLarkChannel(optionsInput) {
|
|
|
1940
2070
|
console.log(
|
|
1941
2071
|
`[eve-lark] helpers.send returned sessionId=${session.id} for chatId=${parsed.chatId}`
|
|
1942
2072
|
);
|
|
2073
|
+
expectFreshCard.add(session.id);
|
|
1943
2074
|
sessionMeta.set(session.id, {
|
|
1944
2075
|
chatId: parsed.chatId,
|
|
1945
2076
|
rootId: parsed.rootId ?? void 0,
|
|
@@ -1983,14 +2114,18 @@ function createLarkChannel(optionsInput) {
|
|
|
1983
2114
|
helpers.waitUntil(
|
|
1984
2115
|
(async () => {
|
|
1985
2116
|
if (pending.cardMessageId && selectedOpt) {
|
|
2117
|
+
const ctrlForBuffer = controllers.get(pending.sessionId);
|
|
2118
|
+
const priorBuffer = ctrlForBuffer?.getBuffer() ?? void 0;
|
|
1986
2119
|
try {
|
|
1987
2120
|
await client.patchCard({
|
|
1988
2121
|
messageId: pending.cardMessageId,
|
|
1989
|
-
card: buildAskAnsweredCard(
|
|
1990
|
-
|
|
1991
|
-
label: selectedOpt.label
|
|
1992
|
-
|
|
2122
|
+
card: buildAskAnsweredCard(
|
|
2123
|
+
pending.request,
|
|
2124
|
+
{ kind: "option", label: selectedOpt.label },
|
|
2125
|
+
priorBuffer
|
|
2126
|
+
)
|
|
1993
2127
|
});
|
|
2128
|
+
ctrlForBuffer?.clearAskRequest();
|
|
1994
2129
|
} catch (e) {
|
|
1995
2130
|
console.warn(
|
|
1996
2131
|
"[eve-lark] patchCard after ask-answer failed:",
|
|
@@ -2101,22 +2236,29 @@ function createLarkChannel(optionsInput) {
|
|
|
2101
2236
|
`[eve-lark] input.requested sessionId=${sessionId} chatId=${info.chatId} count=${requests.length}`
|
|
2102
2237
|
);
|
|
2103
2238
|
for (const req of requests) {
|
|
2104
|
-
const
|
|
2239
|
+
const existingCtrl = controllers.get(sessionId);
|
|
2240
|
+
const canPatchExisting = existingCtrl && existingCtrl.getMessageId() && (options.replyMode === "streaming" || options.replyMode === "streaming-v2");
|
|
2105
2241
|
let cardMessageId;
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2242
|
+
if (canPatchExisting && existingCtrl) {
|
|
2243
|
+
existingCtrl.setAskRequest(req);
|
|
2244
|
+
cardMessageId = existingCtrl.getMessageId();
|
|
2245
|
+
} else {
|
|
2246
|
+
const card = buildAskCard(req);
|
|
2247
|
+
try {
|
|
2248
|
+
const res = await client.sendCard({
|
|
2249
|
+
chatId: info.chatId,
|
|
2250
|
+
card,
|
|
2251
|
+
rootId: info.rootId,
|
|
2252
|
+
parentId: info.parentId
|
|
2253
|
+
});
|
|
2254
|
+
cardMessageId = res.messageId;
|
|
2255
|
+
} catch (e) {
|
|
2256
|
+
console.error(
|
|
2257
|
+
`[eve-lark] ask card send failed (requestId=${req.requestId}):`,
|
|
2258
|
+
e instanceof Error ? e.message : e
|
|
2259
|
+
);
|
|
2260
|
+
continue;
|
|
2261
|
+
}
|
|
2120
2262
|
}
|
|
2121
2263
|
const pending = {
|
|
2122
2264
|
requestId: req.requestId,
|
|
@@ -2155,7 +2297,6 @@ function createLarkChannel(optionsInput) {
|
|
|
2155
2297
|
await deliverReply(sessionId, info, text);
|
|
2156
2298
|
} finally {
|
|
2157
2299
|
await cleanupAckReaction(sessionId);
|
|
2158
|
-
dropController(sessionId);
|
|
2159
2300
|
}
|
|
2160
2301
|
},
|
|
2161
2302
|
async "turn.failed"(data, _channel, ctx) {
|
|
@@ -2196,7 +2337,6 @@ function createLarkChannel(optionsInput) {
|
|
|
2196
2337
|
}
|
|
2197
2338
|
}
|
|
2198
2339
|
await cleanupAckReaction(sessionId);
|
|
2199
|
-
dropController(sessionId);
|
|
2200
2340
|
},
|
|
2201
2341
|
async "session.failed"(data) {
|
|
2202
2342
|
const userText = formatFailureMessage(data, "session failed", { sentence: "session" });
|
|
@@ -2205,11 +2345,29 @@ function createLarkChannel(optionsInput) {
|
|
|
2205
2345
|
`[eve-lark] session.failed: ${userText}` + (errorId ? ` (errorId=${errorId})` : "")
|
|
2206
2346
|
);
|
|
2207
2347
|
},
|
|
2348
|
+
// A new turn is starting within an existing session. Two cases:
|
|
2349
|
+
//
|
|
2350
|
+
// 1. NEW inbound message (the webhook handler set `expectFreshCard`):
|
|
2351
|
+
// force a fresh card so each user message gets its own reply card.
|
|
2352
|
+
// 2. Continuation (HITL answer via button click / freeform, or tool
|
|
2353
|
+
// resume): keep the same card so the whole flow stays on one card.
|
|
2354
|
+
async "turn.started"(_data, _channel, ctx) {
|
|
2355
|
+
const sessionId = ctx?.session?.id;
|
|
2356
|
+
if (!sessionId) return;
|
|
2357
|
+
const ctrl = controllers.get(sessionId);
|
|
2358
|
+
if (ctrl) {
|
|
2359
|
+
if (expectFreshCard.has(sessionId)) {
|
|
2360
|
+
ctrl.resetForNewMessage();
|
|
2361
|
+
expectFreshCard.delete(sessionId);
|
|
2362
|
+
} else {
|
|
2363
|
+
ctrl.resetForNewTurn();
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
},
|
|
2208
2367
|
// Turn ended cleanly. eve fires this after the final message.completed
|
|
2209
2368
|
// (or instead of it when the assistant step ended in tool-calls with no
|
|
2210
|
-
// visible text).
|
|
2211
|
-
//
|
|
2212
|
-
// never coming.
|
|
2369
|
+
// visible text). Just clean up the ack reaction — the controller stays
|
|
2370
|
+
// for the next turn (cleaned by stale-sweep if the session goes quiet).
|
|
2213
2371
|
async "turn.completed"(data, _channel, ctx) {
|
|
2214
2372
|
const sessionId = ctx?.session?.id;
|
|
2215
2373
|
if (!sessionId) return;
|
|
@@ -2217,7 +2375,6 @@ function createLarkChannel(optionsInput) {
|
|
|
2217
2375
|
await cleanupAckReaction(sessionId);
|
|
2218
2376
|
} catch {
|
|
2219
2377
|
}
|
|
2220
|
-
dropController(sessionId);
|
|
2221
2378
|
},
|
|
2222
2379
|
// The agent needs the user to sign in to an external service (e.g.
|
|
2223
2380
|
// GitHub, Slack, Linear). Render a card with a "Sign in with <X>"
|