codex-to-im 1.0.35 → 1.0.37
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/cli.mjs +8 -0
- package/dist/daemon.mjs +318 -42
- package/dist/ui-server.mjs +49 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -36,6 +36,8 @@ var DEFAULT_WORKSPACE_ROOT = path.join(os.homedir(), "cx2im");
|
|
|
36
36
|
var CTI_HOME = process.env.CTI_HOME || DEFAULT_CTI_HOME;
|
|
37
37
|
var CONFIG_PATH = path.join(CTI_HOME, "config.env");
|
|
38
38
|
var CONFIG_V2_PATH = path.join(CTI_HOME, "config.v2.json");
|
|
39
|
+
var DEFAULT_STREAM_STATUS_IDLE_START_SECONDS = 180;
|
|
40
|
+
var DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS = 10;
|
|
39
41
|
function expandHomePath(value) {
|
|
40
42
|
if (!value) return value;
|
|
41
43
|
if (value === "~") return os.homedir();
|
|
@@ -168,6 +170,8 @@ function migrateLegacyEnvToV2(env) {
|
|
|
168
170
|
defaultModel: env.get("CTI_DEFAULT_MODEL") || void 0,
|
|
169
171
|
defaultMode: env.get("CTI_DEFAULT_MODE") || "code",
|
|
170
172
|
historyMessageLimit: parsePositiveInt(env.get("CTI_HISTORY_MESSAGE_LIMIT")) ?? 8,
|
|
173
|
+
streamStatusIdleStartSeconds: parsePositiveInt(env.get("CTI_STREAM_STATUS_IDLE_START_SECONDS")) ?? DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
174
|
+
streamStatusCheckIntervalSeconds: parsePositiveInt(env.get("CTI_STREAM_STATUS_CHECK_INTERVAL_SECONDS")) ?? DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
171
175
|
codexSkipGitRepoCheck: env.has("CTI_CODEX_SKIP_GIT_REPO_CHECK") ? env.get("CTI_CODEX_SKIP_GIT_REPO_CHECK") === "true" : true,
|
|
172
176
|
codexSandboxMode: parseSandboxMode(env.get("CTI_CODEX_SANDBOX_MODE")) ?? "workspace-write",
|
|
173
177
|
codexReasoningEffort: parseReasoningEffort(env.get("CTI_CODEX_REASONING_EFFORT")) ?? "medium",
|
|
@@ -190,6 +194,8 @@ function expandConfig(v2) {
|
|
|
190
194
|
defaultModel: v2.runtime.defaultModel,
|
|
191
195
|
defaultMode: v2.runtime.defaultMode || "code",
|
|
192
196
|
historyMessageLimit: v2.runtime.historyMessageLimit ?? 8,
|
|
197
|
+
streamStatusIdleStartSeconds: v2.runtime.streamStatusIdleStartSeconds ?? DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
198
|
+
streamStatusCheckIntervalSeconds: v2.runtime.streamStatusCheckIntervalSeconds ?? DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
193
199
|
codexSkipGitRepoCheck: v2.runtime.codexSkipGitRepoCheck ?? true,
|
|
194
200
|
codexSandboxMode: v2.runtime.codexSandboxMode ?? "workspace-write",
|
|
195
201
|
codexReasoningEffort: v2.runtime.codexReasoningEffort ?? "medium",
|
|
@@ -214,6 +220,8 @@ function loadConfig() {
|
|
|
214
220
|
defaultWorkspaceRoot: DEFAULT_WORKSPACE_ROOT,
|
|
215
221
|
defaultMode: "code",
|
|
216
222
|
historyMessageLimit: 8,
|
|
223
|
+
streamStatusIdleStartSeconds: DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
224
|
+
streamStatusCheckIntervalSeconds: DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
217
225
|
codexSkipGitRepoCheck: true,
|
|
218
226
|
codexSandboxMode: "workspace-write",
|
|
219
227
|
codexReasoningEffort: "medium",
|
package/dist/daemon.mjs
CHANGED
|
@@ -5123,6 +5123,8 @@ var DEFAULT_WORKSPACE_ROOT = path.join(os.homedir(), "cx2im");
|
|
|
5123
5123
|
var CTI_HOME = process.env.CTI_HOME || DEFAULT_CTI_HOME;
|
|
5124
5124
|
var CONFIG_PATH = path.join(CTI_HOME, "config.env");
|
|
5125
5125
|
var CONFIG_V2_PATH = path.join(CTI_HOME, "config.v2.json");
|
|
5126
|
+
var DEFAULT_STREAM_STATUS_IDLE_START_SECONDS = 180;
|
|
5127
|
+
var DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS = 10;
|
|
5126
5128
|
function expandHomePath(value) {
|
|
5127
5129
|
if (!value) return value;
|
|
5128
5130
|
if (value === "~") return os.homedir();
|
|
@@ -5258,6 +5260,8 @@ function migrateLegacyEnvToV2(env) {
|
|
|
5258
5260
|
defaultModel: env.get("CTI_DEFAULT_MODEL") || void 0,
|
|
5259
5261
|
defaultMode: env.get("CTI_DEFAULT_MODE") || "code",
|
|
5260
5262
|
historyMessageLimit: parsePositiveInt(env.get("CTI_HISTORY_MESSAGE_LIMIT")) ?? 8,
|
|
5263
|
+
streamStatusIdleStartSeconds: parsePositiveInt(env.get("CTI_STREAM_STATUS_IDLE_START_SECONDS")) ?? DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
5264
|
+
streamStatusCheckIntervalSeconds: parsePositiveInt(env.get("CTI_STREAM_STATUS_CHECK_INTERVAL_SECONDS")) ?? DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
5261
5265
|
codexSkipGitRepoCheck: env.has("CTI_CODEX_SKIP_GIT_REPO_CHECK") ? env.get("CTI_CODEX_SKIP_GIT_REPO_CHECK") === "true" : true,
|
|
5262
5266
|
codexSandboxMode: parseSandboxMode(env.get("CTI_CODEX_SANDBOX_MODE")) ?? "workspace-write",
|
|
5263
5267
|
codexReasoningEffort: parseReasoningEffort(env.get("CTI_CODEX_REASONING_EFFORT")) ?? "medium",
|
|
@@ -5284,6 +5288,8 @@ function expandConfig(v2) {
|
|
|
5284
5288
|
defaultModel: v2.runtime.defaultModel,
|
|
5285
5289
|
defaultMode: v2.runtime.defaultMode || "code",
|
|
5286
5290
|
historyMessageLimit: v2.runtime.historyMessageLimit ?? 8,
|
|
5291
|
+
streamStatusIdleStartSeconds: v2.runtime.streamStatusIdleStartSeconds ?? DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
5292
|
+
streamStatusCheckIntervalSeconds: v2.runtime.streamStatusCheckIntervalSeconds ?? DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
5287
5293
|
codexSkipGitRepoCheck: v2.runtime.codexSkipGitRepoCheck ?? true,
|
|
5288
5294
|
codexSandboxMode: v2.runtime.codexSandboxMode ?? "workspace-write",
|
|
5289
5295
|
codexReasoningEffort: v2.runtime.codexReasoningEffort ?? "medium",
|
|
@@ -5308,6 +5314,8 @@ function loadConfig() {
|
|
|
5308
5314
|
defaultWorkspaceRoot: DEFAULT_WORKSPACE_ROOT,
|
|
5309
5315
|
defaultMode: "code",
|
|
5310
5316
|
historyMessageLimit: 8,
|
|
5317
|
+
streamStatusIdleStartSeconds: DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
5318
|
+
streamStatusCheckIntervalSeconds: DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
5311
5319
|
codexSkipGitRepoCheck: true,
|
|
5312
5320
|
codexSandboxMode: "workspace-write",
|
|
5313
5321
|
codexReasoningEffort: "medium",
|
|
@@ -5351,6 +5359,18 @@ function configToSettings(config2) {
|
|
|
5351
5359
|
"bridge_history_message_limit",
|
|
5352
5360
|
String(config2.historyMessageLimit && config2.historyMessageLimit > 0 ? config2.historyMessageLimit : 8)
|
|
5353
5361
|
);
|
|
5362
|
+
m.set(
|
|
5363
|
+
"bridge_stream_status_idle_start_seconds",
|
|
5364
|
+
String(
|
|
5365
|
+
config2.streamStatusIdleStartSeconds && config2.streamStatusIdleStartSeconds > 0 ? config2.streamStatusIdleStartSeconds : DEFAULT_STREAM_STATUS_IDLE_START_SECONDS
|
|
5366
|
+
)
|
|
5367
|
+
);
|
|
5368
|
+
m.set(
|
|
5369
|
+
"bridge_stream_status_check_interval_seconds",
|
|
5370
|
+
String(
|
|
5371
|
+
config2.streamStatusCheckIntervalSeconds && config2.streamStatusCheckIntervalSeconds > 0 ? config2.streamStatusCheckIntervalSeconds : DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS
|
|
5372
|
+
)
|
|
5373
|
+
);
|
|
5354
5374
|
m.set(
|
|
5355
5375
|
"bridge_codex_skip_git_repo_check",
|
|
5356
5376
|
config2.codexSkipGitRepoCheck === true ? "true" : "false"
|
|
@@ -5496,25 +5516,16 @@ function formatElapsed(ms) {
|
|
|
5496
5516
|
const remSec = Math.floor(sec % 60);
|
|
5497
5517
|
return `${min}m ${remSec}s`;
|
|
5498
5518
|
}
|
|
5499
|
-
function
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
${toolMd}` : toolMd;
|
|
5506
|
-
}
|
|
5507
|
-
return content || "\u{1F4AD} Thinking...";
|
|
5519
|
+
function buildStreamingTextContent(text2) {
|
|
5520
|
+
return text2 || "\u{1F4AD} Thinking...";
|
|
5521
|
+
}
|
|
5522
|
+
function buildStreamingToolsContent(tools) {
|
|
5523
|
+
return buildToolProgressMarkdown(tools);
|
|
5508
5524
|
}
|
|
5509
5525
|
function buildFinalCardJson(text2, tools, footer) {
|
|
5510
5526
|
const elements = [];
|
|
5511
|
-
|
|
5527
|
+
const content = preprocessFeishuMarkdown(text2);
|
|
5512
5528
|
const toolMd = buildToolProgressMarkdown(tools);
|
|
5513
|
-
if (toolMd) {
|
|
5514
|
-
content = content ? `${content}
|
|
5515
|
-
|
|
5516
|
-
${toolMd}` : toolMd;
|
|
5517
|
-
}
|
|
5518
5529
|
if (content) {
|
|
5519
5530
|
elements.push({
|
|
5520
5531
|
tag: "markdown",
|
|
@@ -5523,12 +5534,25 @@ ${toolMd}` : toolMd;
|
|
|
5523
5534
|
text_size: "normal"
|
|
5524
5535
|
});
|
|
5525
5536
|
}
|
|
5537
|
+
if (toolMd) {
|
|
5538
|
+
if (elements.length > 0) {
|
|
5539
|
+
elements.push({ tag: "hr" });
|
|
5540
|
+
}
|
|
5541
|
+
elements.push({
|
|
5542
|
+
tag: "markdown",
|
|
5543
|
+
content: toolMd,
|
|
5544
|
+
text_align: "left",
|
|
5545
|
+
text_size: "normal"
|
|
5546
|
+
});
|
|
5547
|
+
}
|
|
5526
5548
|
if (footer) {
|
|
5527
5549
|
const parts = [];
|
|
5528
5550
|
if (footer.status) parts.push(footer.status);
|
|
5529
5551
|
if (footer.elapsed) parts.push(footer.elapsed);
|
|
5530
5552
|
if (parts.length > 0) {
|
|
5531
|
-
elements.
|
|
5553
|
+
if (elements.length > 0) {
|
|
5554
|
+
elements.push({ tag: "hr" });
|
|
5555
|
+
}
|
|
5532
5556
|
elements.push({
|
|
5533
5557
|
tag: "markdown",
|
|
5534
5558
|
content: parts.join(" \xB7 "),
|
|
@@ -5595,6 +5619,8 @@ var DEDUP_MAX = 1e3;
|
|
|
5595
5619
|
var MAX_FILE_SIZE = 20 * 1024 * 1024;
|
|
5596
5620
|
var TYPING_EMOJI = "Typing";
|
|
5597
5621
|
var CARD_THROTTLE_MS = 200;
|
|
5622
|
+
var INITIAL_STREAMING_STATUS = "\u5DF2\u8FD0\u884C 0s";
|
|
5623
|
+
var EMPTY_STREAMING_TOOLS = "";
|
|
5598
5624
|
var MIME_BY_TYPE = {
|
|
5599
5625
|
image: "image/png",
|
|
5600
5626
|
file: "application/octet-stream",
|
|
@@ -5642,6 +5668,9 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5642
5668
|
isStreamingEnabled() {
|
|
5643
5669
|
return this.channelConfig.streamingEnabled !== false;
|
|
5644
5670
|
}
|
|
5671
|
+
supportsStructuredStreamingUi(_chatId) {
|
|
5672
|
+
return this.isStreamingEnabled();
|
|
5673
|
+
}
|
|
5645
5674
|
resolveStreamKey(chatId, streamKey) {
|
|
5646
5675
|
return streamKey?.trim() || chatId;
|
|
5647
5676
|
}
|
|
@@ -5840,13 +5869,29 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5840
5869
|
summary: { content: "\u601D\u8003\u4E2D..." }
|
|
5841
5870
|
},
|
|
5842
5871
|
body: {
|
|
5843
|
-
elements: [
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5872
|
+
elements: [
|
|
5873
|
+
{
|
|
5874
|
+
tag: "markdown",
|
|
5875
|
+
content: "\u{1F4AD} Thinking...",
|
|
5876
|
+
text_align: "left",
|
|
5877
|
+
text_size: "normal",
|
|
5878
|
+
element_id: "streaming_content"
|
|
5879
|
+
},
|
|
5880
|
+
{
|
|
5881
|
+
tag: "markdown",
|
|
5882
|
+
content: EMPTY_STREAMING_TOOLS,
|
|
5883
|
+
text_align: "left",
|
|
5884
|
+
text_size: "normal",
|
|
5885
|
+
element_id: "streaming_tools"
|
|
5886
|
+
},
|
|
5887
|
+
{
|
|
5888
|
+
tag: "markdown",
|
|
5889
|
+
content: INITIAL_STREAMING_STATUS,
|
|
5890
|
+
text_align: "left",
|
|
5891
|
+
text_size: "notation",
|
|
5892
|
+
element_id: "streaming_status"
|
|
5893
|
+
}
|
|
5894
|
+
]
|
|
5850
5895
|
}
|
|
5851
5896
|
};
|
|
5852
5897
|
const createResp = await cardkit.card.create({
|
|
@@ -5888,8 +5933,14 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5888
5933
|
toolCalls: [],
|
|
5889
5934
|
thinking: true,
|
|
5890
5935
|
pendingText: null,
|
|
5936
|
+
pendingStatusText: INITIAL_STREAMING_STATUS,
|
|
5937
|
+
renderedText: "\u{1F4AD} Thinking...",
|
|
5938
|
+
renderedToolsText: EMPTY_STREAMING_TOOLS,
|
|
5939
|
+
renderedStatusText: INITIAL_STREAMING_STATUS,
|
|
5891
5940
|
lastUpdateAt: 0,
|
|
5892
|
-
throttleTimer: null
|
|
5941
|
+
throttleTimer: null,
|
|
5942
|
+
flushInFlight: null,
|
|
5943
|
+
flushQueued: false
|
|
5893
5944
|
});
|
|
5894
5945
|
console.log(`[feishu-adapter] Streaming card created: streamKey=${cardKey}, cardId=${cardId}, msgId=${messageId}`);
|
|
5895
5946
|
return true;
|
|
@@ -5909,12 +5960,43 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5909
5960
|
state.thinking = false;
|
|
5910
5961
|
}
|
|
5911
5962
|
state.pendingText = text2;
|
|
5963
|
+
this.scheduleCardFlush(cardKey);
|
|
5964
|
+
}
|
|
5965
|
+
updateCardStatus(chatId, statusText, streamKey) {
|
|
5966
|
+
const cardKey = this.resolveStreamKey(chatId, streamKey);
|
|
5967
|
+
const state = this.activeCards.get(cardKey);
|
|
5968
|
+
if (!state || !this.restClient) return;
|
|
5969
|
+
state.pendingStatusText = statusText || INITIAL_STREAMING_STATUS;
|
|
5970
|
+
this.scheduleCardFlush(cardKey);
|
|
5971
|
+
}
|
|
5972
|
+
enqueueCardFlush(streamKey) {
|
|
5973
|
+
const state = this.activeCards.get(streamKey);
|
|
5974
|
+
if (!state) return;
|
|
5975
|
+
if (state.flushInFlight) {
|
|
5976
|
+
state.flushQueued = true;
|
|
5977
|
+
return;
|
|
5978
|
+
}
|
|
5979
|
+
state.flushInFlight = this.flushCardUpdate(streamKey).catch((err) => {
|
|
5980
|
+
console.warn("[feishu-adapter] cardElement.content failed:", err instanceof Error ? err.message : err);
|
|
5981
|
+
}).finally(() => {
|
|
5982
|
+
const current = this.activeCards.get(streamKey);
|
|
5983
|
+
if (!current) return;
|
|
5984
|
+
current.flushInFlight = null;
|
|
5985
|
+
if (current.flushQueued) {
|
|
5986
|
+
current.flushQueued = false;
|
|
5987
|
+
this.enqueueCardFlush(streamKey);
|
|
5988
|
+
}
|
|
5989
|
+
});
|
|
5990
|
+
}
|
|
5991
|
+
scheduleCardFlush(streamKey) {
|
|
5992
|
+
const state = this.activeCards.get(streamKey);
|
|
5993
|
+
if (!state) return;
|
|
5912
5994
|
const elapsed = Date.now() - state.lastUpdateAt;
|
|
5913
5995
|
if (elapsed < CARD_THROTTLE_MS && state.lastUpdateAt > 0) {
|
|
5914
5996
|
if (!state.throttleTimer) {
|
|
5915
5997
|
state.throttleTimer = setTimeout(() => {
|
|
5916
5998
|
state.throttleTimer = null;
|
|
5917
|
-
this.
|
|
5999
|
+
this.enqueueCardFlush(streamKey);
|
|
5918
6000
|
}, CARD_THROTTLE_MS - elapsed);
|
|
5919
6001
|
}
|
|
5920
6002
|
return;
|
|
@@ -5923,28 +6005,65 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5923
6005
|
clearTimeout(state.throttleTimer);
|
|
5924
6006
|
state.throttleTimer = null;
|
|
5925
6007
|
}
|
|
5926
|
-
this.
|
|
6008
|
+
this.enqueueCardFlush(streamKey);
|
|
5927
6009
|
}
|
|
5928
6010
|
/**
|
|
5929
6011
|
* Flush pending card update to Feishu API.
|
|
5930
6012
|
*/
|
|
5931
|
-
flushCardUpdate(streamKey) {
|
|
6013
|
+
async flushCardUpdate(streamKey) {
|
|
5932
6014
|
const state = this.activeCards.get(streamKey);
|
|
5933
6015
|
if (!state || !this.restClient) return;
|
|
5934
6016
|
const cardkit = this.restClient.cardkit?.v1;
|
|
5935
6017
|
if (!cardkit?.cardElement?.content) return;
|
|
5936
|
-
const content =
|
|
5937
|
-
state.
|
|
5938
|
-
const
|
|
6018
|
+
const content = buildStreamingTextContent(state.pendingText || "");
|
|
6019
|
+
const toolsText = buildStreamingToolsContent(state.toolCalls) || EMPTY_STREAMING_TOOLS;
|
|
6020
|
+
const statusText = state.pendingStatusText || INITIAL_STREAMING_STATUS;
|
|
6021
|
+
const updates = [];
|
|
6022
|
+
if (content !== state.renderedText) {
|
|
6023
|
+
updates.push({
|
|
6024
|
+
elementId: "streaming_content",
|
|
6025
|
+
content,
|
|
6026
|
+
onSuccess: () => {
|
|
6027
|
+
state.renderedText = content;
|
|
6028
|
+
}
|
|
6029
|
+
});
|
|
6030
|
+
}
|
|
6031
|
+
if (toolsText !== state.renderedToolsText) {
|
|
6032
|
+
updates.push({
|
|
6033
|
+
elementId: "streaming_tools",
|
|
6034
|
+
content: toolsText,
|
|
6035
|
+
onSuccess: () => {
|
|
6036
|
+
state.renderedToolsText = toolsText;
|
|
6037
|
+
}
|
|
6038
|
+
});
|
|
6039
|
+
}
|
|
6040
|
+
if (statusText !== state.renderedStatusText) {
|
|
6041
|
+
updates.push({
|
|
6042
|
+
elementId: "streaming_status",
|
|
6043
|
+
content: statusText,
|
|
6044
|
+
onSuccess: () => {
|
|
6045
|
+
state.renderedStatusText = statusText;
|
|
6046
|
+
}
|
|
6047
|
+
});
|
|
6048
|
+
}
|
|
6049
|
+
if (updates.length === 0) return;
|
|
5939
6050
|
const cardId = state.cardId;
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
6051
|
+
for (const update of updates) {
|
|
6052
|
+
state.sequence++;
|
|
6053
|
+
try {
|
|
6054
|
+
await cardkit.cardElement.content({
|
|
6055
|
+
path: { card_id: cardId, element_id: update.elementId },
|
|
6056
|
+
data: { content: update.content, sequence: state.sequence }
|
|
6057
|
+
});
|
|
6058
|
+
update.onSuccess();
|
|
6059
|
+
state.lastUpdateAt = Date.now();
|
|
6060
|
+
} catch (err) {
|
|
6061
|
+
console.warn(
|
|
6062
|
+
`[feishu-adapter] cardElement.content failed for ${update.elementId}:`,
|
|
6063
|
+
err instanceof Error ? err.message : err
|
|
6064
|
+
);
|
|
6065
|
+
}
|
|
6066
|
+
}
|
|
5948
6067
|
}
|
|
5949
6068
|
/**
|
|
5950
6069
|
* Update tool progress in the streaming card.
|
|
@@ -5954,7 +6073,27 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5954
6073
|
const state = this.activeCards.get(cardKey);
|
|
5955
6074
|
if (!state) return;
|
|
5956
6075
|
state.toolCalls = tools;
|
|
5957
|
-
this.
|
|
6076
|
+
this.scheduleCardFlush(cardKey);
|
|
6077
|
+
}
|
|
6078
|
+
async awaitCardFlushCompletion(streamKey) {
|
|
6079
|
+
while (true) {
|
|
6080
|
+
const state = this.activeCards.get(streamKey);
|
|
6081
|
+
if (!state) return;
|
|
6082
|
+
const inFlight = state.flushInFlight;
|
|
6083
|
+
if (inFlight) {
|
|
6084
|
+
try {
|
|
6085
|
+
await inFlight;
|
|
6086
|
+
} catch {
|
|
6087
|
+
}
|
|
6088
|
+
continue;
|
|
6089
|
+
}
|
|
6090
|
+
if (state.flushQueued) {
|
|
6091
|
+
state.flushQueued = false;
|
|
6092
|
+
this.enqueueCardFlush(streamKey);
|
|
6093
|
+
continue;
|
|
6094
|
+
}
|
|
6095
|
+
return;
|
|
6096
|
+
}
|
|
5958
6097
|
}
|
|
5959
6098
|
/**
|
|
5960
6099
|
* Finalize the streaming card: close streaming mode, update with final content + footer.
|
|
@@ -5976,6 +6115,7 @@ var FeishuAdapter = class extends BaseChannelAdapter {
|
|
|
5976
6115
|
clearTimeout(state.throttleTimer);
|
|
5977
6116
|
state.throttleTimer = null;
|
|
5978
6117
|
}
|
|
6118
|
+
await this.awaitCardFlushCompletion(cardKey);
|
|
5979
6119
|
try {
|
|
5980
6120
|
state.sequence++;
|
|
5981
6121
|
await cardkit.card.settings({
|
|
@@ -6041,6 +6181,9 @@ ${trimmedResponse}`;
|
|
|
6041
6181
|
hasActiveCard(chatId, streamKey) {
|
|
6042
6182
|
return this.activeCards.has(this.resolveStreamKey(chatId, streamKey));
|
|
6043
6183
|
}
|
|
6184
|
+
hasActiveStreamingUi(chatId, streamKey) {
|
|
6185
|
+
return this.hasActiveCard(chatId, streamKey);
|
|
6186
|
+
}
|
|
6044
6187
|
// ── Streaming adapter interface ────────────────────────────────
|
|
6045
6188
|
/**
|
|
6046
6189
|
* Called by bridge-manager on each text SSE event.
|
|
@@ -6070,6 +6213,19 @@ ${trimmedResponse}`;
|
|
|
6070
6213
|
if (!this.isStreamingEnabled()) return;
|
|
6071
6214
|
this.updateToolProgress(chatId, tools, streamKey);
|
|
6072
6215
|
}
|
|
6216
|
+
onStreamStatus(chatId, statusText, streamKey) {
|
|
6217
|
+
if (!this.isStreamingEnabled()) return;
|
|
6218
|
+
const cardKey = this.resolveStreamKey(chatId, streamKey);
|
|
6219
|
+
if (!this.activeCards.has(cardKey)) {
|
|
6220
|
+
const messageId = this.lastIncomingMessageId.get(chatId);
|
|
6221
|
+
this.createStreamingCard(chatId, messageId, cardKey).then((ok) => {
|
|
6222
|
+
if (ok) this.updateCardStatus(chatId, statusText, cardKey);
|
|
6223
|
+
}).catch(() => {
|
|
6224
|
+
});
|
|
6225
|
+
return;
|
|
6226
|
+
}
|
|
6227
|
+
this.updateCardStatus(chatId, statusText, cardKey);
|
|
6228
|
+
}
|
|
6073
6229
|
async onStreamEnd(chatId, status, responseText, streamKey) {
|
|
6074
6230
|
if (!this.isStreamingEnabled()) return false;
|
|
6075
6231
|
return this.finalizeCard(chatId, status, responseText, streamKey);
|
|
@@ -18789,6 +18945,16 @@ function pushStreamFeedbackTools(target, tools) {
|
|
|
18789
18945
|
} catch {
|
|
18790
18946
|
}
|
|
18791
18947
|
}
|
|
18948
|
+
function pushStreamFeedbackStatus(target, text2) {
|
|
18949
|
+
if (typeof target.adapter.onStreamStatus !== "function") return;
|
|
18950
|
+
target.ensureStarted?.();
|
|
18951
|
+
const rendered = renderFeedbackTextForChannel(target.channelType, text2);
|
|
18952
|
+
if (!rendered) return;
|
|
18953
|
+
try {
|
|
18954
|
+
target.adapter.onStreamStatus(target.chatId, rendered, target.streamKey);
|
|
18955
|
+
} catch {
|
|
18956
|
+
}
|
|
18957
|
+
}
|
|
18792
18958
|
async function finalizeStreamFeedback(target, status, text2) {
|
|
18793
18959
|
if (typeof target.adapter.onStreamEnd !== "function") return false;
|
|
18794
18960
|
const rendered = renderFeedbackTextForChannel(target.channelType, text2);
|
|
@@ -18807,6 +18973,8 @@ var STREAM_DEFAULTS = {
|
|
|
18807
18973
|
telegram: { intervalMs: 700, minDeltaChars: 20, maxChars: 3900 },
|
|
18808
18974
|
discord: { intervalMs: 1500, minDeltaChars: 40, maxChars: 1900 }
|
|
18809
18975
|
};
|
|
18976
|
+
var STREAM_STATUS_IDLE_START_MS = 18e4;
|
|
18977
|
+
var STREAM_STATUS_HEARTBEAT_MS = 1e4;
|
|
18810
18978
|
function getStreamConfig(channelType = "telegram") {
|
|
18811
18979
|
const { store } = getBridgeContext();
|
|
18812
18980
|
const defaults = STREAM_DEFAULTS[channelType] || STREAM_DEFAULTS.telegram;
|
|
@@ -18816,6 +18984,21 @@ function getStreamConfig(channelType = "telegram") {
|
|
|
18816
18984
|
const maxChars = parseInt(store.getSetting(`${prefix}max_chars`) || "", 10) || defaults.maxChars;
|
|
18817
18985
|
return { intervalMs, minDeltaChars, maxChars };
|
|
18818
18986
|
}
|
|
18987
|
+
function getStructuredStreamStatusConfig() {
|
|
18988
|
+
const { store } = getBridgeContext();
|
|
18989
|
+
const idleStartSeconds = parseInt(store.getSetting("bridge_stream_status_idle_start_seconds") || "", 10);
|
|
18990
|
+
const heartbeatSeconds = parseInt(store.getSetting("bridge_stream_status_check_interval_seconds") || "", 10);
|
|
18991
|
+
return {
|
|
18992
|
+
idleStartMs: Math.max(
|
|
18993
|
+
0,
|
|
18994
|
+
(Number.isFinite(idleStartSeconds) && idleStartSeconds > 0 ? idleStartSeconds : STREAM_STATUS_IDLE_START_MS / 1e3) * 1e3
|
|
18995
|
+
),
|
|
18996
|
+
heartbeatMs: Math.max(
|
|
18997
|
+
1e3,
|
|
18998
|
+
(Number.isFinite(heartbeatSeconds) && heartbeatSeconds > 0 ? heartbeatSeconds : STREAM_STATUS_HEARTBEAT_MS / 1e3) * 1e3
|
|
18999
|
+
)
|
|
19000
|
+
};
|
|
19001
|
+
}
|
|
18819
19002
|
function flushPreview(adapter, state, config2) {
|
|
18820
19003
|
if (state.degraded || !adapter.sendPreview) return;
|
|
18821
19004
|
const text2 = state.pendingText.length > config2.maxChars ? state.pendingText.slice(0, config2.maxChars) + "..." : state.pendingText;
|
|
@@ -18826,12 +19009,48 @@ function flushPreview(adapter, state, config2) {
|
|
|
18826
19009
|
}).catch(() => {
|
|
18827
19010
|
});
|
|
18828
19011
|
}
|
|
19012
|
+
function formatRuntimeDuration(ms) {
|
|
19013
|
+
const totalSeconds = Math.max(0, Math.floor(ms / 1e3));
|
|
19014
|
+
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
19015
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
19016
|
+
const seconds = totalSeconds % 60;
|
|
19017
|
+
if (totalMinutes < 60) {
|
|
19018
|
+
return seconds > 0 ? `${totalMinutes}m ${seconds}s` : `${totalMinutes}m`;
|
|
19019
|
+
}
|
|
19020
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
19021
|
+
const minutes = totalMinutes % 60;
|
|
19022
|
+
if (minutes === 0 && seconds === 0) return `${hours}h`;
|
|
19023
|
+
if (seconds === 0) return `${hours}h ${minutes}m`;
|
|
19024
|
+
return `${hours}h ${minutes}m ${seconds}s`;
|
|
19025
|
+
}
|
|
19026
|
+
function formatInteractiveRuntimeStatus(elapsedMs, silentMs) {
|
|
19027
|
+
const parts = [`\u5DF2\u8FD0\u884C ${formatRuntimeDuration(elapsedMs)}`];
|
|
19028
|
+
if (typeof silentMs === "number" && silentMs >= 0) {
|
|
19029
|
+
parts.push(`\u6700\u8FD1 ${formatRuntimeDuration(silentMs)} \u65E0\u65B0\u8F93\u51FA`);
|
|
19030
|
+
}
|
|
19031
|
+
return parts.join("\uFF0C");
|
|
19032
|
+
}
|
|
18829
19033
|
async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
18830
19034
|
const binding = resolve(msg.address);
|
|
18831
19035
|
const streamKey = buildInteractiveStreamKey(binding.codepilotSessionId, msg.messageId);
|
|
19036
|
+
const nowMs = deps.nowMs ?? (() => Date.now());
|
|
19037
|
+
const setIntervalFn = deps.setIntervalFn ?? ((callback, intervalMs) => setInterval(callback, intervalMs));
|
|
19038
|
+
const clearIntervalFn = deps.clearIntervalFn ?? ((handle) => clearInterval(handle));
|
|
19039
|
+
const processMessageImpl = deps.processMessageImpl ?? processMessage;
|
|
19040
|
+
const forwardPermissionRequestImpl = deps.forwardPermissionRequestImpl ?? forwardPermissionRequest;
|
|
19041
|
+
const structuredStreamStatusConfig = getStructuredStreamStatusConfig();
|
|
19042
|
+
const streamStatusIdleDetectionStartMs = Math.max(
|
|
19043
|
+
0,
|
|
19044
|
+
deps.streamStatusIdleDetectionStartMs ?? structuredStreamStatusConfig.idleStartMs
|
|
19045
|
+
);
|
|
19046
|
+
const streamStatusHeartbeatMs = Math.max(
|
|
19047
|
+
1e3,
|
|
19048
|
+
deps.streamStatusHeartbeatMs ?? structuredStreamStatusConfig.heartbeatMs
|
|
19049
|
+
);
|
|
18832
19050
|
adapter.onMessageStart?.(msg.address.chatId, streamKey);
|
|
18833
19051
|
const taskAbort = new AbortController();
|
|
18834
19052
|
const taskId = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
19053
|
+
const taskStartedAt = nowMs();
|
|
18835
19054
|
deps.resetMirrorSessionForInteractiveRun(binding.codepilotSessionId);
|
|
18836
19055
|
const taskState = {
|
|
18837
19056
|
id: taskId,
|
|
@@ -18842,7 +19061,8 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18842
19061
|
streamKey,
|
|
18843
19062
|
sessionId: binding.codepilotSessionId,
|
|
18844
19063
|
hasStreamingCards: false,
|
|
18845
|
-
|
|
19064
|
+
structuredStreamUiActive: false,
|
|
19065
|
+
lastActivityAt: taskStartedAt,
|
|
18846
19066
|
idleReminderSent: false,
|
|
18847
19067
|
streamFinalized: false,
|
|
18848
19068
|
uiEnded: false,
|
|
@@ -18905,6 +19125,33 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18905
19125
|
chatId: msg.address.chatId,
|
|
18906
19126
|
streamKey
|
|
18907
19127
|
};
|
|
19128
|
+
const supportsPersistentStreamStatus = hasStreamingCards && adapter.provider === "feishu" && typeof adapter.onStreamStatus === "function";
|
|
19129
|
+
const supportsStructuredStreamUi = supportsPersistentStreamStatus && (adapter.supportsStructuredStreamingUi?.(msg.address.chatId) ?? true);
|
|
19130
|
+
const syncStructuredStreamUiState = () => {
|
|
19131
|
+
if (!supportsStructuredStreamUi || taskState.structuredStreamUiActive) return;
|
|
19132
|
+
if (adapter.hasActiveStreamingUi?.(msg.address.chatId, streamKey)) {
|
|
19133
|
+
taskState.structuredStreamUiActive = true;
|
|
19134
|
+
}
|
|
19135
|
+
};
|
|
19136
|
+
const pushRunningStatus = (silentMs) => {
|
|
19137
|
+
if (!supportsStructuredStreamUi || streamStatusUpdatesClosed) return;
|
|
19138
|
+
pushStreamFeedbackStatus(
|
|
19139
|
+
streamFeedbackTarget,
|
|
19140
|
+
formatInteractiveRuntimeStatus(nowMs() - taskStartedAt, silentMs)
|
|
19141
|
+
);
|
|
19142
|
+
syncStructuredStreamUiState();
|
|
19143
|
+
};
|
|
19144
|
+
let streamStatusHeartbeat = null;
|
|
19145
|
+
let streamStatusUpdatesClosed = false;
|
|
19146
|
+
const clearStreamStatusHeartbeat = () => {
|
|
19147
|
+
if (streamStatusHeartbeat == null) return;
|
|
19148
|
+
clearIntervalFn(streamStatusHeartbeat);
|
|
19149
|
+
streamStatusHeartbeat = null;
|
|
19150
|
+
};
|
|
19151
|
+
const stopStructuredStreamStatusUpdates = () => {
|
|
19152
|
+
streamStatusUpdatesClosed = true;
|
|
19153
|
+
clearStreamStatusHeartbeat();
|
|
19154
|
+
};
|
|
18908
19155
|
const onStreamCardText = hasStreamingCards ? (fullText) => {
|
|
18909
19156
|
if (!deps.isCurrentInteractiveTask(binding.codepilotSessionId, taskId)) return;
|
|
18910
19157
|
pushStreamFeedbackText(
|
|
@@ -18925,6 +19172,8 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18925
19172
|
if (hasStreamingCards) {
|
|
18926
19173
|
pushStreamFeedbackTools(streamFeedbackTarget, Array.from(toolCallTracker.values()));
|
|
18927
19174
|
}
|
|
19175
|
+
pushRunningStatus(null);
|
|
19176
|
+
syncStructuredStreamUiState();
|
|
18928
19177
|
};
|
|
18929
19178
|
const onPartialText = (fullText) => {
|
|
18930
19179
|
if (!deps.isCurrentInteractiveTask(binding.codepilotSessionId, taskId)) return;
|
|
@@ -18932,17 +19181,38 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18932
19181
|
deps.recordInteractiveHealthProgress(binding.codepilotSessionId, "text");
|
|
18933
19182
|
previewOnPartialText?.(fullText);
|
|
18934
19183
|
onStreamCardText?.(fullText);
|
|
19184
|
+
pushRunningStatus(null);
|
|
19185
|
+
syncStructuredStreamUiState();
|
|
18935
19186
|
};
|
|
19187
|
+
if (supportsStructuredStreamUi) {
|
|
19188
|
+
pushRunningStatus(null);
|
|
19189
|
+
streamStatusHeartbeat = setIntervalFn(() => {
|
|
19190
|
+
if (streamStatusUpdatesClosed) {
|
|
19191
|
+
clearStreamStatusHeartbeat();
|
|
19192
|
+
return;
|
|
19193
|
+
}
|
|
19194
|
+
if (!deps.isCurrentInteractiveTask(binding.codepilotSessionId, taskId) || taskAbort.signal.aborted) {
|
|
19195
|
+
clearStreamStatusHeartbeat();
|
|
19196
|
+
return;
|
|
19197
|
+
}
|
|
19198
|
+
const elapsedMs = nowMs() - taskStartedAt;
|
|
19199
|
+
if (elapsedMs < streamStatusIdleDetectionStartMs) return;
|
|
19200
|
+
const silentMs = nowMs() - taskState.lastActivityAt;
|
|
19201
|
+
if (silentMs < streamStatusHeartbeatMs) return;
|
|
19202
|
+
pushRunningStatus(silentMs);
|
|
19203
|
+
syncStructuredStreamUiState();
|
|
19204
|
+
}, streamStatusHeartbeatMs);
|
|
19205
|
+
}
|
|
18936
19206
|
let finalOutcome = "failed";
|
|
18937
19207
|
let finalOutcomeDetail;
|
|
18938
19208
|
let shouldRecordHealthEnd = true;
|
|
18939
19209
|
try {
|
|
18940
19210
|
const promptText = text2 || (attachments && attachments.length > 0 ? "Describe this image." : "");
|
|
18941
|
-
const result = await
|
|
19211
|
+
const result = await processMessageImpl(
|
|
18942
19212
|
binding,
|
|
18943
19213
|
promptText,
|
|
18944
19214
|
async (perm) => {
|
|
18945
|
-
await
|
|
19215
|
+
await forwardPermissionRequestImpl(
|
|
18946
19216
|
adapter,
|
|
18947
19217
|
msg.address,
|
|
18948
19218
|
perm.permissionRequestId,
|
|
@@ -18974,6 +19244,7 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
18974
19244
|
}
|
|
18975
19245
|
let cardFinalized = false;
|
|
18976
19246
|
if (hasStreamingCards) {
|
|
19247
|
+
stopStructuredStreamStatusUpdates();
|
|
18977
19248
|
cardFinalized = await finalizeStreamFeedback(
|
|
18978
19249
|
streamFeedbackTarget,
|
|
18979
19250
|
result.hasError ? "error" : "completed",
|
|
@@ -19008,6 +19279,7 @@ async function runInteractiveMessage(adapter, msg, text2, attachments, deps) {
|
|
|
19008
19279
|
finalOutcome = result.hasError ? "failed" : "completed";
|
|
19009
19280
|
finalOutcomeDetail = result.hasError ? result.errorMessage?.trim() || void 0 : void 0;
|
|
19010
19281
|
} finally {
|
|
19282
|
+
stopStructuredStreamStatusUpdates();
|
|
19011
19283
|
if (previewState) {
|
|
19012
19284
|
if (previewState.throttleTimer) {
|
|
19013
19285
|
clearTimeout(previewState.throttleTimer);
|
|
@@ -19052,6 +19324,9 @@ function buildInteractiveIdleReminderNotice() {
|
|
|
19052
19324
|
"\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
19325
|
].join("\n");
|
|
19054
19326
|
}
|
|
19327
|
+
function shouldSkipIdleReminder(task) {
|
|
19328
|
+
return task.adapter.provider === "feishu" && task.structuredStreamUiActive;
|
|
19329
|
+
}
|
|
19055
19330
|
function createInteractiveRuntime(getState2, options, deps) {
|
|
19056
19331
|
function getQueuedCount(sessionId) {
|
|
19057
19332
|
return getState2().queuedCounts.get(sessionId) || 0;
|
|
@@ -19110,6 +19385,7 @@ function createInteractiveRuntime(getState2, options, deps) {
|
|
|
19110
19385
|
const now2 = Date.now();
|
|
19111
19386
|
const tasks = Array.from(getState2().activeTasks.values());
|
|
19112
19387
|
for (const task of tasks) {
|
|
19388
|
+
if (shouldSkipIdleReminder(task)) continue;
|
|
19113
19389
|
if (task.idleReminderSent) continue;
|
|
19114
19390
|
if (now2 - task.lastActivityAt < options.idleReminderMs) continue;
|
|
19115
19391
|
await remindIdleInteractiveTask(task);
|
package/dist/ui-server.mjs
CHANGED
|
@@ -4604,6 +4604,8 @@ var DEFAULT_WORKSPACE_ROOT = path.join(os.homedir(), "cx2im");
|
|
|
4604
4604
|
var CTI_HOME = process.env.CTI_HOME || DEFAULT_CTI_HOME;
|
|
4605
4605
|
var CONFIG_PATH = path.join(CTI_HOME, "config.env");
|
|
4606
4606
|
var CONFIG_V2_PATH = path.join(CTI_HOME, "config.v2.json");
|
|
4607
|
+
var DEFAULT_STREAM_STATUS_IDLE_START_SECONDS = 180;
|
|
4608
|
+
var DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS = 10;
|
|
4607
4609
|
function expandHomePath(value) {
|
|
4608
4610
|
if (!value) return value;
|
|
4609
4611
|
if (value === "~") return os.homedir();
|
|
@@ -4739,6 +4741,8 @@ function migrateLegacyEnvToV2(env) {
|
|
|
4739
4741
|
defaultModel: env.get("CTI_DEFAULT_MODEL") || void 0,
|
|
4740
4742
|
defaultMode: env.get("CTI_DEFAULT_MODE") || "code",
|
|
4741
4743
|
historyMessageLimit: parsePositiveInt(env.get("CTI_HISTORY_MESSAGE_LIMIT")) ?? 8,
|
|
4744
|
+
streamStatusIdleStartSeconds: parsePositiveInt(env.get("CTI_STREAM_STATUS_IDLE_START_SECONDS")) ?? DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
4745
|
+
streamStatusCheckIntervalSeconds: parsePositiveInt(env.get("CTI_STREAM_STATUS_CHECK_INTERVAL_SECONDS")) ?? DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
4742
4746
|
codexSkipGitRepoCheck: env.has("CTI_CODEX_SKIP_GIT_REPO_CHECK") ? env.get("CTI_CODEX_SKIP_GIT_REPO_CHECK") === "true" : true,
|
|
4743
4747
|
codexSandboxMode: parseSandboxMode(env.get("CTI_CODEX_SANDBOX_MODE")) ?? "workspace-write",
|
|
4744
4748
|
codexReasoningEffort: parseReasoningEffort(env.get("CTI_CODEX_REASONING_EFFORT")) ?? "medium",
|
|
@@ -4765,6 +4769,8 @@ function expandConfig(v2) {
|
|
|
4765
4769
|
defaultModel: v2.runtime.defaultModel,
|
|
4766
4770
|
defaultMode: v2.runtime.defaultMode || "code",
|
|
4767
4771
|
historyMessageLimit: v2.runtime.historyMessageLimit ?? 8,
|
|
4772
|
+
streamStatusIdleStartSeconds: v2.runtime.streamStatusIdleStartSeconds ?? DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
4773
|
+
streamStatusCheckIntervalSeconds: v2.runtime.streamStatusCheckIntervalSeconds ?? DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
4768
4774
|
codexSkipGitRepoCheck: v2.runtime.codexSkipGitRepoCheck ?? true,
|
|
4769
4775
|
codexSandboxMode: v2.runtime.codexSandboxMode ?? "workspace-write",
|
|
4770
4776
|
codexReasoningEffort: v2.runtime.codexReasoningEffort ?? "medium",
|
|
@@ -4784,6 +4790,8 @@ function buildV2FileFromExpandedConfig(config, current) {
|
|
|
4784
4790
|
defaultModel: config.defaultModel,
|
|
4785
4791
|
defaultMode: config.defaultMode,
|
|
4786
4792
|
historyMessageLimit: config.historyMessageLimit,
|
|
4793
|
+
streamStatusIdleStartSeconds: config.streamStatusIdleStartSeconds,
|
|
4794
|
+
streamStatusCheckIntervalSeconds: config.streamStatusCheckIntervalSeconds,
|
|
4787
4795
|
codexSkipGitRepoCheck: config.codexSkipGitRepoCheck,
|
|
4788
4796
|
codexSandboxMode: config.codexSandboxMode,
|
|
4789
4797
|
codexReasoningEffort: config.codexReasoningEffort,
|
|
@@ -4814,6 +4822,8 @@ function loadConfig() {
|
|
|
4814
4822
|
defaultWorkspaceRoot: DEFAULT_WORKSPACE_ROOT,
|
|
4815
4823
|
defaultMode: "code",
|
|
4816
4824
|
historyMessageLimit: 8,
|
|
4825
|
+
streamStatusIdleStartSeconds: DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
|
|
4826
|
+
streamStatusCheckIntervalSeconds: DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
|
|
4817
4827
|
codexSkipGitRepoCheck: true,
|
|
4818
4828
|
codexSandboxMode: "workspace-write",
|
|
4819
4829
|
codexReasoningEffort: "medium",
|
|
@@ -4845,6 +4855,12 @@ function saveConfig(config) {
|
|
|
4845
4855
|
if (next.runtime.historyMessageLimit !== void 0) {
|
|
4846
4856
|
out += formatEnvLine("CTI_HISTORY_MESSAGE_LIMIT", String(next.runtime.historyMessageLimit));
|
|
4847
4857
|
}
|
|
4858
|
+
if (next.runtime.streamStatusIdleStartSeconds !== void 0) {
|
|
4859
|
+
out += formatEnvLine("CTI_STREAM_STATUS_IDLE_START_SECONDS", String(next.runtime.streamStatusIdleStartSeconds));
|
|
4860
|
+
}
|
|
4861
|
+
if (next.runtime.streamStatusCheckIntervalSeconds !== void 0) {
|
|
4862
|
+
out += formatEnvLine("CTI_STREAM_STATUS_CHECK_INTERVAL_SECONDS", String(next.runtime.streamStatusCheckIntervalSeconds));
|
|
4863
|
+
}
|
|
4848
4864
|
if (next.runtime.codexSkipGitRepoCheck !== void 0) {
|
|
4849
4865
|
out += formatEnvLine("CTI_CODEX_SKIP_GIT_REPO_CHECK", String(next.runtime.codexSkipGitRepoCheck));
|
|
4850
4866
|
}
|
|
@@ -4917,6 +4933,18 @@ function configToSettings(config) {
|
|
|
4917
4933
|
"bridge_history_message_limit",
|
|
4918
4934
|
String(config.historyMessageLimit && config.historyMessageLimit > 0 ? config.historyMessageLimit : 8)
|
|
4919
4935
|
);
|
|
4936
|
+
m.set(
|
|
4937
|
+
"bridge_stream_status_idle_start_seconds",
|
|
4938
|
+
String(
|
|
4939
|
+
config.streamStatusIdleStartSeconds && config.streamStatusIdleStartSeconds > 0 ? config.streamStatusIdleStartSeconds : DEFAULT_STREAM_STATUS_IDLE_START_SECONDS
|
|
4940
|
+
)
|
|
4941
|
+
);
|
|
4942
|
+
m.set(
|
|
4943
|
+
"bridge_stream_status_check_interval_seconds",
|
|
4944
|
+
String(
|
|
4945
|
+
config.streamStatusCheckIntervalSeconds && config.streamStatusCheckIntervalSeconds > 0 ? config.streamStatusCheckIntervalSeconds : DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS
|
|
4946
|
+
)
|
|
4947
|
+
);
|
|
4920
4948
|
m.set(
|
|
4921
4949
|
"bridge_codex_skip_git_repo_check",
|
|
4922
4950
|
config.codexSkipGitRepoCheck === true ? "true" : "false"
|
|
@@ -7626,6 +7654,8 @@ function configToPayload(config) {
|
|
|
7626
7654
|
availableModels: availableCodexModels,
|
|
7627
7655
|
defaultMode: config.defaultMode,
|
|
7628
7656
|
historyMessageLimit: config.historyMessageLimit ?? 8,
|
|
7657
|
+
streamStatusIdleStartSeconds: config.streamStatusIdleStartSeconds ?? 180,
|
|
7658
|
+
streamStatusCheckIntervalSeconds: config.streamStatusCheckIntervalSeconds ?? 10,
|
|
7629
7659
|
codexSkipGitRepoCheck: config.codexSkipGitRepoCheck === true,
|
|
7630
7660
|
codexSandboxMode: config.codexSandboxMode || "workspace-write",
|
|
7631
7661
|
codexReasoningEffort: config.codexReasoningEffort || "medium",
|
|
@@ -7649,6 +7679,8 @@ function mergeConfig(payload) {
|
|
|
7649
7679
|
defaultModel: rawDefaultModel === void 0 ? current.defaultModel : rawDefaultModel === "" ? void 0 : availableCodexModelSlugs.has(rawDefaultModel) ? rawDefaultModel : current.defaultModel,
|
|
7650
7680
|
defaultMode: payload.defaultMode === "plan" || payload.defaultMode === "ask" ? payload.defaultMode : "code",
|
|
7651
7681
|
historyMessageLimit: asPositiveInt(payload.historyMessageLimit) || current.historyMessageLimit || 8,
|
|
7682
|
+
streamStatusIdleStartSeconds: asPositiveInt(payload.streamStatusIdleStartSeconds) || current.streamStatusIdleStartSeconds || 180,
|
|
7683
|
+
streamStatusCheckIntervalSeconds: asPositiveInt(payload.streamStatusCheckIntervalSeconds) || current.streamStatusCheckIntervalSeconds || 10,
|
|
7652
7684
|
codexSkipGitRepoCheck: payload.codexSkipGitRepoCheck === true,
|
|
7653
7685
|
codexSandboxMode: payload.codexSandboxMode === "read-only" || payload.codexSandboxMode === "danger-full-access" ? payload.codexSandboxMode : "workspace-write",
|
|
7654
7686
|
codexReasoningEffort: payload.codexReasoningEffort === "minimal" || payload.codexReasoningEffort === "low" || payload.codexReasoningEffort === "high" || payload.codexReasoningEffort === "xhigh" ? payload.codexReasoningEffort : "medium",
|
|
@@ -9486,6 +9518,14 @@ function renderHtml() {
|
|
|
9486
9518
|
/history \u8FD4\u56DE\u6761\u6570
|
|
9487
9519
|
<input id="historyMessageLimit" type="number" min="1" max="20" value="8" />
|
|
9488
9520
|
</label>
|
|
9521
|
+
<label>
|
|
9522
|
+
\u9759\u9ED8\u68C0\u6D4B\u542F\u52A8\u65F6\u957F\uFF08\u79D2\uFF09
|
|
9523
|
+
<input id="streamStatusIdleStartSeconds" type="number" min="1" value="180" />
|
|
9524
|
+
</label>
|
|
9525
|
+
<label>
|
|
9526
|
+
\u9759\u9ED8\u68C0\u6D4B\u95F4\u9694\uFF08\u79D2\uFF09
|
|
9527
|
+
<input id="streamStatusCheckIntervalSeconds" type="number" min="1" value="10" />
|
|
9528
|
+
</label>
|
|
9489
9529
|
</div>
|
|
9490
9530
|
<label>
|
|
9491
9531
|
\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4
|
|
@@ -9515,7 +9555,7 @@ function renderHtml() {
|
|
|
9515
9555
|
</select>
|
|
9516
9556
|
</label>
|
|
9517
9557
|
</div>
|
|
9518
|
-
<div class="small">\u672A\u7ED1\u5B9A\u7684 IM \u804A\u5929\u4F1A\u5148\u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF08\u7B49\u540C <code>/t 0</code>\uFF09\uFF1B\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u53EA\u7528\u4E8E <code>/new proj1</code> \u8FD9\u7C7B\u76F8\u5BF9\u9879\u76EE\u540D\u3002\u7559\u7A7A\u65F6\u4F1A\u6309\u5F53\u524D\u7CFB\u7EDF\u81EA\u52A8\u56DE\u9000\u5230 <code>~/cx2im</code>\u3002\u9ED8\u8BA4\u6A21\u578B\u5019\u9009\u9879\u6765\u81EA\u542F\u52A8\u65F6\u8BFB\u53D6\u7684 Codex \u6A21\u578B\u7F13\u5B58\uFF1A\u9690\u85CF\u6A21\u578B\u4E0D\u4F1A\u5C55\u793A\uFF0CCLI only \u6A21\u578B\u4F1A\u6807\u6210\u201C\u4EC5 IM / CLI\u201D\u3002\u7559\u7A7A\u5219\u7EE7\u7EED\u8DDF\u968F Codex \u5F53\u524D\u9ED8\u8BA4\u6A21\u578B\u3002\u6587\u4EF6\u7CFB\u7EDF\u6743\u9650\u662F\u5168\u5C40\u9ED8\u8BA4\u503C\uFF0C\u601D\u8003\u7EA7\u522B\u53EF\u5728 IM \u4F1A\u8BDD\u91CC\u518D\u5355\u72EC\u8986\u76D6\u3002</div>
|
|
9558
|
+
<div class="small">\u672A\u7ED1\u5B9A\u7684 IM \u804A\u5929\u4F1A\u5148\u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF08\u7B49\u540C <code>/t 0</code>\uFF09\uFF1B\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u53EA\u7528\u4E8E <code>/new proj1</code> \u8FD9\u7C7B\u76F8\u5BF9\u9879\u76EE\u540D\u3002\u7559\u7A7A\u65F6\u4F1A\u6309\u5F53\u524D\u7CFB\u7EDF\u81EA\u52A8\u56DE\u9000\u5230 <code>~/cx2im</code>\u3002\u9ED8\u8BA4\u6A21\u578B\u5019\u9009\u9879\u6765\u81EA\u542F\u52A8\u65F6\u8BFB\u53D6\u7684 Codex \u6A21\u578B\u7F13\u5B58\uFF1A\u9690\u85CF\u6A21\u578B\u4E0D\u4F1A\u5C55\u793A\uFF0CCLI only \u6A21\u578B\u4F1A\u6807\u6210\u201C\u4EC5 IM / CLI\u201D\u3002\u7559\u7A7A\u5219\u7EE7\u7EED\u8DDF\u968F Codex \u5F53\u524D\u9ED8\u8BA4\u6A21\u578B\u3002\u6587\u4EF6\u7CFB\u7EDF\u6743\u9650\u662F\u5168\u5C40\u9ED8\u8BA4\u503C\uFF0C\u601D\u8003\u7EA7\u522B\u53EF\u5728 IM \u4F1A\u8BDD\u91CC\u518D\u5355\u72EC\u8986\u76D6\u3002\u9759\u9ED8\u68C0\u6D4B\u914D\u7F6E\u53EA\u5F71\u54CD\u98DE\u4E66\u957F\u4EFB\u52A1\u5E95\u90E8\u201C\u6700\u8FD1 X \u65E0\u65B0\u8F93\u51FA\u201D\u7684\u51FA\u73B0\u65F6\u673A\u3002</div>
|
|
9519
9559
|
<div class="small">\u5F53\u524D\u9700\u8981\u91CD\u542F Bridge \u7684\u914D\u7F6E\uFF1A<code>Runtime</code>\u3001<code>\u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650</code>\u3001<code>\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex</code>\u3002\u901A\u9053\u5B9E\u4F8B\u7684\u63A5\u5165\u914D\u7F6E\u8BF7\u5728\u201C\u901A\u9053\u201D\u9875\u7EF4\u62A4\u3002</div>
|
|
9520
9560
|
<div class="checkbox-row">
|
|
9521
9561
|
<label class="checkbox"><input id="autoApprove" type="checkbox" /> \u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650</label>
|
|
@@ -9835,6 +9875,8 @@ function renderHtml() {
|
|
|
9835
9875
|
runtime: document.getElementById('runtime').value,
|
|
9836
9876
|
defaultMode: document.getElementById('defaultMode').value,
|
|
9837
9877
|
historyMessageLimit: document.getElementById('historyMessageLimit').value,
|
|
9878
|
+
streamStatusIdleStartSeconds: document.getElementById('streamStatusIdleStartSeconds').value,
|
|
9879
|
+
streamStatusCheckIntervalSeconds: document.getElementById('streamStatusCheckIntervalSeconds').value,
|
|
9838
9880
|
defaultWorkspaceRoot: document.getElementById('defaultWorkspaceRoot').value,
|
|
9839
9881
|
defaultModel: document.getElementById('defaultModel').value,
|
|
9840
9882
|
codexSkipGitRepoCheck: document.getElementById('codexSkipGitRepoCheck').checked,
|
|
@@ -10012,6 +10054,8 @@ function renderHtml() {
|
|
|
10012
10054
|
defaultModel: '\u9ED8\u8BA4\u6A21\u578B',
|
|
10013
10055
|
defaultMode: '\u9ED8\u8BA4\u6A21\u5F0F',
|
|
10014
10056
|
historyMessageLimit: '/history \u8FD4\u56DE\u6761\u6570',
|
|
10057
|
+
streamStatusIdleStartSeconds: '\u9759\u9ED8\u68C0\u6D4B\u542F\u52A8\u65F6\u957F',
|
|
10058
|
+
streamStatusCheckIntervalSeconds: '\u9759\u9ED8\u68C0\u6D4B\u95F4\u9694',
|
|
10015
10059
|
codexSkipGitRepoCheck: '\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex',
|
|
10016
10060
|
codexSandboxMode: 'Codex \u6587\u4EF6\u7CFB\u7EDF\u6743\u9650',
|
|
10017
10061
|
codexReasoningEffort: 'Codex \u601D\u8003\u7EA7\u522B',
|
|
@@ -10033,6 +10077,8 @@ function renderHtml() {
|
|
|
10033
10077
|
'defaultModel',
|
|
10034
10078
|
'defaultMode',
|
|
10035
10079
|
'historyMessageLimit',
|
|
10080
|
+
'streamStatusIdleStartSeconds',
|
|
10081
|
+
'streamStatusCheckIntervalSeconds',
|
|
10036
10082
|
'codexSandboxMode',
|
|
10037
10083
|
'codexReasoningEffort',
|
|
10038
10084
|
'uiAllowLan',
|
|
@@ -10604,6 +10650,8 @@ function renderHtml() {
|
|
|
10604
10650
|
document.getElementById('runtime').value = config.runtime || 'codex';
|
|
10605
10651
|
document.getElementById('defaultMode').value = config.defaultMode || 'code';
|
|
10606
10652
|
document.getElementById('historyMessageLimit').value = String(config.historyMessageLimit || 8);
|
|
10653
|
+
document.getElementById('streamStatusIdleStartSeconds').value = String(config.streamStatusIdleStartSeconds || 180);
|
|
10654
|
+
document.getElementById('streamStatusCheckIntervalSeconds').value = String(config.streamStatusCheckIntervalSeconds || 10);
|
|
10607
10655
|
document.getElementById('defaultWorkspaceRoot').value = config.defaultWorkspaceRoot || '';
|
|
10608
10656
|
renderDefaultModelOptions(config);
|
|
10609
10657
|
document.getElementById('codexSkipGitRepoCheck').checked = config.codexSkipGitRepoCheck === true;
|
package/package.json
CHANGED