codex-to-im 1.0.35 → 1.0.36
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/daemon.mjs +272 -42
- package/package.json +1 -1
package/dist/daemon.mjs
CHANGED
|
@@ -5496,25 +5496,16 @@ function formatElapsed(ms) {
|
|
|
5496
5496
|
const remSec = Math.floor(sec % 60);
|
|
5497
5497
|
return `${min}m ${remSec}s`;
|
|
5498
5498
|
}
|
|
5499
|
-
function
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
${toolMd}` : toolMd;
|
|
5506
|
-
}
|
|
5507
|
-
return content || "\u{1F4AD} Thinking...";
|
|
5499
|
+
function buildStreamingTextContent(text2) {
|
|
5500
|
+
return text2 || "\u{1F4AD} Thinking...";
|
|
5501
|
+
}
|
|
5502
|
+
function buildStreamingToolsContent(tools) {
|
|
5503
|
+
return buildToolProgressMarkdown(tools);
|
|
5508
5504
|
}
|
|
5509
5505
|
function buildFinalCardJson(text2, tools, footer) {
|
|
5510
5506
|
const elements = [];
|
|
5511
|
-
|
|
5507
|
+
const content = preprocessFeishuMarkdown(text2);
|
|
5512
5508
|
const toolMd = buildToolProgressMarkdown(tools);
|
|
5513
|
-
if (toolMd) {
|
|
5514
|
-
content = content ? `${content}
|
|
5515
|
-
|
|
5516
|
-
${toolMd}` : toolMd;
|
|
5517
|
-
}
|
|
5518
5509
|
if (content) {
|
|
5519
5510
|
elements.push({
|
|
5520
5511
|
tag: "markdown",
|
|
@@ -5523,12 +5514,25 @@ ${toolMd}` : toolMd;
|
|
|
5523
5514
|
text_size: "normal"
|
|
5524
5515
|
});
|
|
5525
5516
|
}
|
|
5517
|
+
if (toolMd) {
|
|
5518
|
+
if (elements.length > 0) {
|
|
5519
|
+
elements.push({ tag: "hr" });
|
|
5520
|
+
}
|
|
5521
|
+
elements.push({
|
|
5522
|
+
tag: "markdown",
|
|
5523
|
+
content: toolMd,
|
|
5524
|
+
text_align: "left",
|
|
5525
|
+
text_size: "normal"
|
|
5526
|
+
});
|
|
5527
|
+
}
|
|
5526
5528
|
if (footer) {
|
|
5527
5529
|
const parts = [];
|
|
5528
5530
|
if (footer.status) parts.push(footer.status);
|
|
5529
5531
|
if (footer.elapsed) parts.push(footer.elapsed);
|
|
5530
5532
|
if (parts.length > 0) {
|
|
5531
|
-
elements.
|
|
5533
|
+
if (elements.length > 0) {
|
|
5534
|
+
elements.push({ tag: "hr" });
|
|
5535
|
+
}
|
|
5532
5536
|
elements.push({
|
|
5533
5537
|
tag: "markdown",
|
|
5534
5538
|
content: parts.join(" \xB7 "),
|
|
@@ -5595,6 +5599,8 @@ var DEDUP_MAX = 1e3;
|
|
|
5595
5599
|
var MAX_FILE_SIZE = 20 * 1024 * 1024;
|
|
5596
5600
|
var TYPING_EMOJI = "Typing";
|
|
5597
5601
|
var CARD_THROTTLE_MS = 200;
|
|
5602
|
+
var INITIAL_STREAMING_STATUS = "\u5DF2\u8FD0\u884C 0s";
|
|
5603
|
+
var EMPTY_STREAMING_TOOLS = "";
|
|
5598
5604
|
var MIME_BY_TYPE = {
|
|
5599
5605
|
image: "image/png",
|
|
5600
5606
|
file: "application/octet-stream",
|
|
@@ -5642,6 +5648,9 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5642
5648
|
isStreamingEnabled() {
|
|
5643
5649
|
return this.channelConfig.streamingEnabled !== false;
|
|
5644
5650
|
}
|
|
5651
|
+
supportsStructuredStreamingUi(_chatId) {
|
|
5652
|
+
return this.isStreamingEnabled();
|
|
5653
|
+
}
|
|
5645
5654
|
resolveStreamKey(chatId, streamKey) {
|
|
5646
5655
|
return streamKey?.trim() || chatId;
|
|
5647
5656
|
}
|
|
@@ -5840,13 +5849,29 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5840
5849
|
summary: { content: "\u601D\u8003\u4E2D..." }
|
|
5841
5850
|
},
|
|
5842
5851
|
body: {
|
|
5843
|
-
elements: [
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5852
|
+
elements: [
|
|
5853
|
+
{
|
|
5854
|
+
tag: "markdown",
|
|
5855
|
+
content: "\u{1F4AD} Thinking...",
|
|
5856
|
+
text_align: "left",
|
|
5857
|
+
text_size: "normal",
|
|
5858
|
+
element_id: "streaming_content"
|
|
5859
|
+
},
|
|
5860
|
+
{
|
|
5861
|
+
tag: "markdown",
|
|
5862
|
+
content: EMPTY_STREAMING_TOOLS,
|
|
5863
|
+
text_align: "left",
|
|
5864
|
+
text_size: "normal",
|
|
5865
|
+
element_id: "streaming_tools"
|
|
5866
|
+
},
|
|
5867
|
+
{
|
|
5868
|
+
tag: "markdown",
|
|
5869
|
+
content: INITIAL_STREAMING_STATUS,
|
|
5870
|
+
text_align: "left",
|
|
5871
|
+
text_size: "notation",
|
|
5872
|
+
element_id: "streaming_status"
|
|
5873
|
+
}
|
|
5874
|
+
]
|
|
5850
5875
|
}
|
|
5851
5876
|
};
|
|
5852
5877
|
const createResp = await cardkit.card.create({
|
|
@@ -5888,8 +5913,14 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5888
5913
|
toolCalls: [],
|
|
5889
5914
|
thinking: true,
|
|
5890
5915
|
pendingText: null,
|
|
5916
|
+
pendingStatusText: INITIAL_STREAMING_STATUS,
|
|
5917
|
+
renderedText: "\u{1F4AD} Thinking...",
|
|
5918
|
+
renderedToolsText: EMPTY_STREAMING_TOOLS,
|
|
5919
|
+
renderedStatusText: INITIAL_STREAMING_STATUS,
|
|
5891
5920
|
lastUpdateAt: 0,
|
|
5892
|
-
throttleTimer: null
|
|
5921
|
+
throttleTimer: null,
|
|
5922
|
+
flushInFlight: null,
|
|
5923
|
+
flushQueued: false
|
|
5893
5924
|
});
|
|
5894
5925
|
console.log(`[feishu-adapter] Streaming card created: streamKey=${cardKey}, cardId=${cardId}, msgId=${messageId}`);
|
|
5895
5926
|
return true;
|
|
@@ -5909,12 +5940,43 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5909
5940
|
state.thinking = false;
|
|
5910
5941
|
}
|
|
5911
5942
|
state.pendingText = text2;
|
|
5943
|
+
this.scheduleCardFlush(cardKey);
|
|
5944
|
+
}
|
|
5945
|
+
updateCardStatus(chatId, statusText, streamKey) {
|
|
5946
|
+
const cardKey = this.resolveStreamKey(chatId, streamKey);
|
|
5947
|
+
const state = this.activeCards.get(cardKey);
|
|
5948
|
+
if (!state || !this.restClient) return;
|
|
5949
|
+
state.pendingStatusText = statusText || INITIAL_STREAMING_STATUS;
|
|
5950
|
+
this.scheduleCardFlush(cardKey);
|
|
5951
|
+
}
|
|
5952
|
+
enqueueCardFlush(streamKey) {
|
|
5953
|
+
const state = this.activeCards.get(streamKey);
|
|
5954
|
+
if (!state) return;
|
|
5955
|
+
if (state.flushInFlight) {
|
|
5956
|
+
state.flushQueued = true;
|
|
5957
|
+
return;
|
|
5958
|
+
}
|
|
5959
|
+
state.flushInFlight = this.flushCardUpdate(streamKey).catch((err) => {
|
|
5960
|
+
console.warn("[feishu-adapter] cardElement.content failed:", err instanceof Error ? err.message : err);
|
|
5961
|
+
}).finally(() => {
|
|
5962
|
+
const current = this.activeCards.get(streamKey);
|
|
5963
|
+
if (!current) return;
|
|
5964
|
+
current.flushInFlight = null;
|
|
5965
|
+
if (current.flushQueued) {
|
|
5966
|
+
current.flushQueued = false;
|
|
5967
|
+
this.enqueueCardFlush(streamKey);
|
|
5968
|
+
}
|
|
5969
|
+
});
|
|
5970
|
+
}
|
|
5971
|
+
scheduleCardFlush(streamKey) {
|
|
5972
|
+
const state = this.activeCards.get(streamKey);
|
|
5973
|
+
if (!state) return;
|
|
5912
5974
|
const elapsed = Date.now() - state.lastUpdateAt;
|
|
5913
5975
|
if (elapsed < CARD_THROTTLE_MS && state.lastUpdateAt > 0) {
|
|
5914
5976
|
if (!state.throttleTimer) {
|
|
5915
5977
|
state.throttleTimer = setTimeout(() => {
|
|
5916
5978
|
state.throttleTimer = null;
|
|
5917
|
-
this.
|
|
5979
|
+
this.enqueueCardFlush(streamKey);
|
|
5918
5980
|
}, CARD_THROTTLE_MS - elapsed);
|
|
5919
5981
|
}
|
|
5920
5982
|
return;
|
|
@@ -5923,28 +5985,65 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5923
5985
|
clearTimeout(state.throttleTimer);
|
|
5924
5986
|
state.throttleTimer = null;
|
|
5925
5987
|
}
|
|
5926
|
-
this.
|
|
5988
|
+
this.enqueueCardFlush(streamKey);
|
|
5927
5989
|
}
|
|
5928
5990
|
/**
|
|
5929
5991
|
* Flush pending card update to Feishu API.
|
|
5930
5992
|
*/
|
|
5931
|
-
flushCardUpdate(streamKey) {
|
|
5993
|
+
async flushCardUpdate(streamKey) {
|
|
5932
5994
|
const state = this.activeCards.get(streamKey);
|
|
5933
5995
|
if (!state || !this.restClient) return;
|
|
5934
5996
|
const cardkit = this.restClient.cardkit?.v1;
|
|
5935
5997
|
if (!cardkit?.cardElement?.content) return;
|
|
5936
|
-
const content =
|
|
5937
|
-
state.
|
|
5938
|
-
const
|
|
5998
|
+
const content = buildStreamingTextContent(state.pendingText || "");
|
|
5999
|
+
const toolsText = buildStreamingToolsContent(state.toolCalls) || EMPTY_STREAMING_TOOLS;
|
|
6000
|
+
const statusText = state.pendingStatusText || INITIAL_STREAMING_STATUS;
|
|
6001
|
+
const updates = [];
|
|
6002
|
+
if (content !== state.renderedText) {
|
|
6003
|
+
updates.push({
|
|
6004
|
+
elementId: "streaming_content",
|
|
6005
|
+
content,
|
|
6006
|
+
onSuccess: () => {
|
|
6007
|
+
state.renderedText = content;
|
|
6008
|
+
}
|
|
6009
|
+
});
|
|
6010
|
+
}
|
|
6011
|
+
if (toolsText !== state.renderedToolsText) {
|
|
6012
|
+
updates.push({
|
|
6013
|
+
elementId: "streaming_tools",
|
|
6014
|
+
content: toolsText,
|
|
6015
|
+
onSuccess: () => {
|
|
6016
|
+
state.renderedToolsText = toolsText;
|
|
6017
|
+
}
|
|
6018
|
+
});
|
|
6019
|
+
}
|
|
6020
|
+
if (statusText !== state.renderedStatusText) {
|
|
6021
|
+
updates.push({
|
|
6022
|
+
elementId: "streaming_status",
|
|
6023
|
+
content: statusText,
|
|
6024
|
+
onSuccess: () => {
|
|
6025
|
+
state.renderedStatusText = statusText;
|
|
6026
|
+
}
|
|
6027
|
+
});
|
|
6028
|
+
}
|
|
6029
|
+
if (updates.length === 0) return;
|
|
5939
6030
|
const cardId = state.cardId;
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
6031
|
+
for (const update of updates) {
|
|
6032
|
+
state.sequence++;
|
|
6033
|
+
try {
|
|
6034
|
+
await cardkit.cardElement.content({
|
|
6035
|
+
path: { card_id: cardId, element_id: update.elementId },
|
|
6036
|
+
data: { content: update.content, sequence: state.sequence }
|
|
6037
|
+
});
|
|
6038
|
+
update.onSuccess();
|
|
6039
|
+
state.lastUpdateAt = Date.now();
|
|
6040
|
+
} catch (err) {
|
|
6041
|
+
console.warn(
|
|
6042
|
+
`[feishu-adapter] cardElement.content failed for ${update.elementId}:`,
|
|
6043
|
+
err instanceof Error ? err.message : err
|
|
6044
|
+
);
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
5948
6047
|
}
|
|
5949
6048
|
/**
|
|
5950
6049
|
* Update tool progress in the streaming card.
|
|
@@ -5954,7 +6053,27 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5954
6053
|
const state = this.activeCards.get(cardKey);
|
|
5955
6054
|
if (!state) return;
|
|
5956
6055
|
state.toolCalls = tools;
|
|
5957
|
-
this.
|
|
6056
|
+
this.scheduleCardFlush(cardKey);
|
|
6057
|
+
}
|
|
6058
|
+
async awaitCardFlushCompletion(streamKey) {
|
|
6059
|
+
while (true) {
|
|
6060
|
+
const state = this.activeCards.get(streamKey);
|
|
6061
|
+
if (!state) return;
|
|
6062
|
+
const inFlight = state.flushInFlight;
|
|
6063
|
+
if (inFlight) {
|
|
6064
|
+
try {
|
|
6065
|
+
await inFlight;
|
|
6066
|
+
} catch {
|
|
6067
|
+
}
|
|
6068
|
+
continue;
|
|
6069
|
+
}
|
|
6070
|
+
if (state.flushQueued) {
|
|
6071
|
+
state.flushQueued = false;
|
|
6072
|
+
this.enqueueCardFlush(streamKey);
|
|
6073
|
+
continue;
|
|
6074
|
+
}
|
|
6075
|
+
return;
|
|
6076
|
+
}
|
|
5958
6077
|
}
|
|
5959
6078
|
/**
|
|
5960
6079
|
* Finalize the streaming card: close streaming mode, update with final content + footer.
|
|
@@ -5976,6 +6095,7 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5976
6095
|
clearTimeout(state.throttleTimer);
|
|
5977
6096
|
state.throttleTimer = null;
|
|
5978
6097
|
}
|
|
6098
|
+
await this.awaitCardFlushCompletion(cardKey);
|
|
5979
6099
|
try {
|
|
5980
6100
|
state.sequence++;
|
|
5981
6101
|
await cardkit.card.settings({
|
|
@@ -6041,6 +6161,9 @@ ${trimmedResponse}`;
|
|
|
6041
6161
|
hasActiveCard(chatId, streamKey) {
|
|
6042
6162
|
return this.activeCards.has(this.resolveStreamKey(chatId, streamKey));
|
|
6043
6163
|
}
|
|
6164
|
+
hasActiveStreamingUi(chatId, streamKey) {
|
|
6165
|
+
return this.hasActiveCard(chatId, streamKey);
|
|
6166
|
+
}
|
|
6044
6167
|
// ── Streaming adapter interface ────────────────────────────────
|
|
6045
6168
|
/**
|
|
6046
6169
|
* Called by bridge-manager on each text SSE event.
|
|
@@ -6070,6 +6193,19 @@ ${trimmedResponse}`;
|
|
|
6070
6193
|
if (!this.isStreamingEnabled()) return;
|
|
6071
6194
|
this.updateToolProgress(chatId, tools, streamKey);
|
|
6072
6195
|
}
|
|
6196
|
+
onStreamStatus(chatId, statusText, streamKey) {
|
|
6197
|
+
if (!this.isStreamingEnabled()) return;
|
|
6198
|
+
const cardKey = this.resolveStreamKey(chatId, streamKey);
|
|
6199
|
+
if (!this.activeCards.has(cardKey)) {
|
|
6200
|
+
const messageId = this.lastIncomingMessageId.get(chatId);
|
|
6201
|
+
this.createStreamingCard(chatId, messageId, cardKey).then((ok) => {
|
|
6202
|
+
if (ok) this.updateCardStatus(chatId, statusText, cardKey);
|
|
6203
|
+
}).catch(() => {
|
|
6204
|
+
});
|
|
6205
|
+
return;
|
|
6206
|
+
}
|
|
6207
|
+
this.updateCardStatus(chatId, statusText, cardKey);
|
|
6208
|
+
}
|
|
6073
6209
|
async onStreamEnd(chatId, status, responseText, streamKey) {
|
|
6074
6210
|
if (!this.isStreamingEnabled()) return false;
|
|
6075
6211
|
return this.finalizeCard(chatId, status, responseText, streamKey);
|
|
@@ -18789,6 +18925,16 @@ function pushStreamFeedbackTools(target, tools) {
|
|
|
18789
18925
|
} catch {
|
|
18790
18926
|
}
|
|
18791
18927
|
}
|
|
18928
|
+
function pushStreamFeedbackStatus(target, text2) {
|
|
18929
|
+
if (typeof target.adapter.onStreamStatus !== "function") return;
|
|
18930
|
+
target.ensureStarted?.();
|
|
18931
|
+
const rendered = renderFeedbackTextForChannel(target.channelType, text2);
|
|
18932
|
+
if (!rendered) return;
|
|
18933
|
+
try {
|
|
18934
|
+
target.adapter.onStreamStatus(target.chatId, rendered, target.streamKey);
|
|
18935
|
+
} catch {
|
|
18936
|
+
}
|
|
18937
|
+
}
|
|
18792
18938
|
async function finalizeStreamFeedback(target, status, text2) {
|
|
18793
18939
|
if (typeof target.adapter.onStreamEnd !== "function") return false;
|
|
18794
18940
|
const rendered = renderFeedbackTextForChannel(target.channelType, text2);
|
|
@@ -18807,6 +18953,7 @@ var STREAM_DEFAULTS = {
|
|
|
18807
18953
|
telegram: { intervalMs: 700, minDeltaChars: 20, maxChars: 3900 },
|
|
18808
18954
|
discord: { intervalMs: 1500, minDeltaChars: 40, maxChars: 1900 }
|
|
18809
18955
|
};
|
|
18956
|
+
var STREAM_STATUS_HEARTBEAT_MS = 1e4;
|
|
18810
18957
|
function getStreamConfig(channelType = "telegram") {
|
|
18811
18958
|
const { store } = getBridgeContext();
|
|
18812
18959
|
const defaults = STREAM_DEFAULTS[channelType] || STREAM_DEFAULTS.telegram;
|
|
@@ -18826,12 +18973,40 @@ function flushPreview(adapter, state, config2) {
|
|
|
18826
18973
|
}).catch(() => {
|
|
18827
18974
|
});
|
|
18828
18975
|
}
|
|
18976
|
+
function formatRuntimeDuration(ms) {
|
|
18977
|
+
const totalSeconds = Math.max(0, Math.floor(ms / 1e3));
|
|
18978
|
+
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
18979
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
18980
|
+
const seconds = totalSeconds % 60;
|
|
18981
|
+
if (totalMinutes < 60) {
|
|
18982
|
+
return seconds > 0 ? `${totalMinutes}m ${seconds}s` : `${totalMinutes}m`;
|
|
18983
|
+
}
|
|
18984
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
18985
|
+
const minutes = totalMinutes % 60;
|
|
18986
|
+
if (minutes === 0 && seconds === 0) return `${hours}h`;
|
|
18987
|
+
if (seconds === 0) return `${hours}h ${minutes}m`;
|
|
18988
|
+
return `${hours}h ${minutes}m ${seconds}s`;
|
|
18989
|
+
}
|
|
18990
|
+
function formatInteractiveRuntimeStatus(elapsedMs, silentMs) {
|
|
18991
|
+
const parts = [`\u5DF2\u8FD0\u884C ${formatRuntimeDuration(elapsedMs)}`];
|
|
18992
|
+
if (typeof silentMs === "number" && silentMs >= 0) {
|
|
18993
|
+
parts.push(`\u6700\u8FD1 ${formatRuntimeDuration(silentMs)} \u65E0\u65B0\u8F93\u51FA`);
|
|
18994
|
+
}
|
|
18995
|
+
return parts.join("\uFF0C");
|
|
18996
|
+
}
|
|
18829
18997
|
async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
18830
18998
|
const binding = resolve(msg.address);
|
|
18831
18999
|
const streamKey = buildInteractiveStreamKey(binding.codepilotSessionId, msg.messageId);
|
|
19000
|
+
const nowMs = deps.nowMs ?? (() => Date.now());
|
|
19001
|
+
const setIntervalFn = deps.setIntervalFn ?? ((callback, intervalMs) => setInterval(callback, intervalMs));
|
|
19002
|
+
const clearIntervalFn = deps.clearIntervalFn ?? ((handle) => clearInterval(handle));
|
|
19003
|
+
const processMessageImpl = deps.processMessageImpl ?? processMessage;
|
|
19004
|
+
const forwardPermissionRequestImpl = deps.forwardPermissionRequestImpl ?? forwardPermissionRequest;
|
|
19005
|
+
const streamStatusHeartbeatMs = Math.max(1e3, deps.streamStatusHeartbeatMs ?? STREAM_STATUS_HEARTBEAT_MS);
|
|
18832
19006
|
adapter.onMessageStart?.(msg.address.chatId, streamKey);
|
|
18833
19007
|
const taskAbort = new AbortController();
|
|
18834
19008
|
const taskId = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
19009
|
+
const taskStartedAt = nowMs();
|
|
18835
19010
|
deps.resetMirrorSessionForInteractiveRun(binding.codepilotSessionId);
|
|
18836
19011
|
const taskState = {
|
|
18837
19012
|
id: taskId,
|
|
@@ -18842,7 +19017,8 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18842
19017
|
streamKey,
|
|
18843
19018
|
sessionId: binding.codepilotSessionId,
|
|
18844
19019
|
hasStreamingCards: false,
|
|
18845
|
-
|
|
19020
|
+
structuredStreamUiActive: false,
|
|
19021
|
+
lastActivityAt: taskStartedAt,
|
|
18846
19022
|
idleReminderSent: false,
|
|
18847
19023
|
streamFinalized: false,
|
|
18848
19024
|
uiEnded: false,
|
|
@@ -18905,6 +19081,33 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18905
19081
|
chatId: msg.address.chatId,
|
|
18906
19082
|
streamKey
|
|
18907
19083
|
};
|
|
19084
|
+
const supportsPersistentStreamStatus = hasStreamingCards && adapter.provider === "feishu" && typeof adapter.onStreamStatus === "function";
|
|
19085
|
+
const supportsStructuredStreamUi = supportsPersistentStreamStatus && (adapter.supportsStructuredStreamingUi?.(msg.address.chatId) ?? true);
|
|
19086
|
+
const syncStructuredStreamUiState = () => {
|
|
19087
|
+
if (!supportsStructuredStreamUi || taskState.structuredStreamUiActive) return;
|
|
19088
|
+
if (adapter.hasActiveStreamingUi?.(msg.address.chatId, streamKey)) {
|
|
19089
|
+
taskState.structuredStreamUiActive = true;
|
|
19090
|
+
}
|
|
19091
|
+
};
|
|
19092
|
+
const pushRunningStatus = (silentMs) => {
|
|
19093
|
+
if (!supportsStructuredStreamUi || streamStatusUpdatesClosed) return;
|
|
19094
|
+
pushStreamFeedbackStatus(
|
|
19095
|
+
streamFeedbackTarget,
|
|
19096
|
+
formatInteractiveRuntimeStatus(nowMs() - taskStartedAt, silentMs)
|
|
19097
|
+
);
|
|
19098
|
+
syncStructuredStreamUiState();
|
|
19099
|
+
};
|
|
19100
|
+
let streamStatusHeartbeat = null;
|
|
19101
|
+
let streamStatusUpdatesClosed = false;
|
|
19102
|
+
const clearStreamStatusHeartbeat = () => {
|
|
19103
|
+
if (streamStatusHeartbeat == null) return;
|
|
19104
|
+
clearIntervalFn(streamStatusHeartbeat);
|
|
19105
|
+
streamStatusHeartbeat = null;
|
|
19106
|
+
};
|
|
19107
|
+
const stopStructuredStreamStatusUpdates = () => {
|
|
19108
|
+
streamStatusUpdatesClosed = true;
|
|
19109
|
+
clearStreamStatusHeartbeat();
|
|
19110
|
+
};
|
|
18908
19111
|
const onStreamCardText = hasStreamingCards ? (fullText) => {
|
|
18909
19112
|
if (!deps.isCurrentInteractiveTask(binding.codepilotSessionId, taskId)) return;
|
|
18910
19113
|
pushStreamFeedbackText(
|
|
@@ -18925,6 +19128,8 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18925
19128
|
if (hasStreamingCards) {
|
|
18926
19129
|
pushStreamFeedbackTools(streamFeedbackTarget, Array.from(toolCallTracker.values()));
|
|
18927
19130
|
}
|
|
19131
|
+
pushRunningStatus(null);
|
|
19132
|
+
syncStructuredStreamUiState();
|
|
18928
19133
|
};
|
|
18929
19134
|
const onPartialText = (fullText) => {
|
|
18930
19135
|
if (!deps.isCurrentInteractiveTask(binding.codepilotSessionId, taskId)) return;
|
|
@@ -18932,17 +19137,36 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18932
19137
|
deps.recordInteractiveHealthProgress(binding.codepilotSessionId, "text");
|
|
18933
19138
|
previewOnPartialText?.(fullText);
|
|
18934
19139
|
onStreamCardText?.(fullText);
|
|
19140
|
+
pushRunningStatus(null);
|
|
19141
|
+
syncStructuredStreamUiState();
|
|
18935
19142
|
};
|
|
19143
|
+
if (supportsStructuredStreamUi) {
|
|
19144
|
+
pushRunningStatus(null);
|
|
19145
|
+
streamStatusHeartbeat = setIntervalFn(() => {
|
|
19146
|
+
if (streamStatusUpdatesClosed) {
|
|
19147
|
+
clearStreamStatusHeartbeat();
|
|
19148
|
+
return;
|
|
19149
|
+
}
|
|
19150
|
+
if (!deps.isCurrentInteractiveTask(binding.codepilotSessionId, taskId) || taskAbort.signal.aborted) {
|
|
19151
|
+
clearStreamStatusHeartbeat();
|
|
19152
|
+
return;
|
|
19153
|
+
}
|
|
19154
|
+
const silentMs = nowMs() - taskState.lastActivityAt;
|
|
19155
|
+
if (silentMs < streamStatusHeartbeatMs) return;
|
|
19156
|
+
pushRunningStatus(silentMs);
|
|
19157
|
+
syncStructuredStreamUiState();
|
|
19158
|
+
}, streamStatusHeartbeatMs);
|
|
19159
|
+
}
|
|
18936
19160
|
let finalOutcome = "failed";
|
|
18937
19161
|
let finalOutcomeDetail;
|
|
18938
19162
|
let shouldRecordHealthEnd = true;
|
|
18939
19163
|
try {
|
|
18940
19164
|
const promptText = text2 || (attachments && attachments.length > 0 ? "Describe this image." : "");
|
|
18941
|
-
const result = await
|
|
19165
|
+
const result = await processMessageImpl(
|
|
18942
19166
|
binding,
|
|
18943
19167
|
promptText,
|
|
18944
19168
|
async (perm) => {
|
|
18945
|
-
await
|
|
19169
|
+
await forwardPermissionRequestImpl(
|
|
18946
19170
|
adapter,
|
|
18947
19171
|
msg.address,
|
|
18948
19172
|
perm.permissionRequestId,
|
|
@@ -18974,6 +19198,7 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18974
19198
|
}
|
|
18975
19199
|
let cardFinalized = false;
|
|
18976
19200
|
if (hasStreamingCards) {
|
|
19201
|
+
stopStructuredStreamStatusUpdates();
|
|
18977
19202
|
cardFinalized = await finalizeStreamFeedback(
|
|
18978
19203
|
streamFeedbackTarget,
|
|
18979
19204
|
result.hasError ? "error" : "completed",
|
|
@@ -19008,6 +19233,7 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
19008
19233
|
finalOutcome = result.hasError ? "failed" : "completed";
|
|
19009
19234
|
finalOutcomeDetail = result.hasError ? result.errorMessage?.trim() || void 0 : void 0;
|
|
19010
19235
|
} finally {
|
|
19236
|
+
stopStructuredStreamStatusUpdates();
|
|
19011
19237
|
if (previewState) {
|
|
19012
19238
|
if (previewState.throttleTimer) {
|
|
19013
19239
|
clearTimeout(previewState.throttleTimer);
|
|
@@ -19052,6 +19278,9 @@ function buildInteractiveIdleReminderNotice() {
|
|
|
19052
19278
|
"\u7CFB\u7EDF\u4E0D\u4F1A\u81EA\u52A8\u7EC8\u6B62\u5B83\uFF1B\u5982\u679C\u4F60\u4ECD\u5728\u5BF9\u5E94\u7EBF\u7A0B\uFF0C\u53EF\u53D1\u9001 `/stop` \u4E3B\u52A8\u505C\u6B62\uFF1B\u5982\u679C\u5DF2\u7ECF\u5207\u5230\u522B\u7684\u7EBF\u7A0B\uFF0C\u9700\u8981\u5148\u5207\u56DE\u5BF9\u5E94\u7EBF\u7A0B\u3002"
|
|
19053
19279
|
].join("\n");
|
|
19054
19280
|
}
|
|
19281
|
+
function shouldSkipIdleReminder(task) {
|
|
19282
|
+
return task.adapter.provider === "feishu" && task.structuredStreamUiActive;
|
|
19283
|
+
}
|
|
19055
19284
|
function createInteractiveRuntime(getState2, options, deps) {
|
|
19056
19285
|
function getQueuedCount(sessionId) {
|
|
19057
19286
|
return getState2().queuedCounts.get(sessionId) || 0;
|
|
@@ -19110,6 +19339,7 @@ function createInteractiveRuntime(getState2, options, deps) {
|
|
|
19110
19339
|
const now2 = Date.now();
|
|
19111
19340
|
const tasks = Array.from(getState2().activeTasks.values());
|
|
19112
19341
|
for (const task of tasks) {
|
|
19342
|
+
if (shouldSkipIdleReminder(task)) continue;
|
|
19113
19343
|
if (task.idleReminderSent) continue;
|
|
19114
19344
|
if (now2 - task.lastActivityAt < options.idleReminderMs) continue;
|
|
19115
19345
|
await remindIdleInteractiveTask(task);
|
package/package.json
CHANGED