@love-moon/conductor-cli 0.2.40 → 0.2.42
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/bin/conductor-fire.js +114 -16
- package/package.json +5 -5
package/bin/conductor-fire.js
CHANGED
|
@@ -848,6 +848,10 @@ async function main() {
|
|
|
848
848
|
let nextInitialPrompt =
|
|
849
849
|
taskContext.shouldProcessInitialPrompt ? cliArgs.initialPrompt : "";
|
|
850
850
|
let pendingRefreshSessionRequest = null;
|
|
851
|
+
// Only the first iteration should deliver the configured pre_prompt; any
|
|
852
|
+
// subsequent refresh-session rebuild must skip it so users don't see the
|
|
853
|
+
// pre_prompt bubble duplicated.
|
|
854
|
+
let nextShouldProcessPrePrompt = Boolean(taskContext.shouldProcessPrePrompt);
|
|
851
855
|
|
|
852
856
|
const sessionCommandLine = resolveAiSessionCommandLine(
|
|
853
857
|
cliArgs.backend,
|
|
@@ -930,7 +934,6 @@ async function main() {
|
|
|
930
934
|
...(cliArgs.sessionOptions || {}),
|
|
931
935
|
...(sessionCommandLine ? { commandLine: sessionCommandLine } : {}),
|
|
932
936
|
logger: { log },
|
|
933
|
-
...(resolvedPrePrompt ? { prePrompt: resolvedPrePrompt } : {}),
|
|
934
937
|
sessionStoreKey: taskContext.taskId ? `task-${taskContext.taskId}` : undefined,
|
|
935
938
|
resumePersistedSession: Boolean(!nextResumeSessionId && taskContext.taskId),
|
|
936
939
|
});
|
|
@@ -947,6 +950,8 @@ async function main() {
|
|
|
947
950
|
backendName: cliArgs.backend,
|
|
948
951
|
resumeSessionId: nextResumeSessionId,
|
|
949
952
|
daemonName: resolvedDaemonName,
|
|
953
|
+
prePrompt: resolvedPrePrompt || "",
|
|
954
|
+
shouldProcessPrePrompt: Boolean(resolvedPrePrompt) && nextShouldProcessPrePrompt,
|
|
950
955
|
});
|
|
951
956
|
reconnectRunner = runner;
|
|
952
957
|
if (pendingRemoteStopEvent) {
|
|
@@ -993,6 +998,7 @@ async function main() {
|
|
|
993
998
|
if (refreshedSessionId) {
|
|
994
999
|
nextResumeSessionId = refreshedSessionId;
|
|
995
1000
|
nextInitialPrompt = "";
|
|
1001
|
+
nextShouldProcessPrePrompt = false;
|
|
996
1002
|
pendingRefreshSessionRequest = refreshSessionRequest;
|
|
997
1003
|
continue;
|
|
998
1004
|
}
|
|
@@ -1467,6 +1473,9 @@ async function ensureTaskContext(conductor, opts) {
|
|
|
1467
1473
|
appUrl: null,
|
|
1468
1474
|
shouldProcessInitialPrompt: Boolean(opts.initialPrompt),
|
|
1469
1475
|
initialPromptDelivery: opts.initialPrompt ? "synthetic" : "none",
|
|
1476
|
+
// Daemon provided the task id, so this fire process is the first attach
|
|
1477
|
+
// for that task — it should inject the configured pre_prompt once.
|
|
1478
|
+
shouldProcessPrePrompt: true,
|
|
1470
1479
|
};
|
|
1471
1480
|
}
|
|
1472
1481
|
|
|
@@ -1493,6 +1502,9 @@ async function ensureTaskContext(conductor, opts) {
|
|
|
1493
1502
|
appUrl: session.app_url || null,
|
|
1494
1503
|
shouldProcessInitialPrompt: Boolean(opts.initialPrompt),
|
|
1495
1504
|
initialPromptDelivery: opts.initialPrompt ? "queued" : "none",
|
|
1505
|
+
// Newly created task — pre_prompt should run exactly once right after
|
|
1506
|
+
// the backend session is announced, before any real user message.
|
|
1507
|
+
shouldProcessPrePrompt: true,
|
|
1496
1508
|
};
|
|
1497
1509
|
}
|
|
1498
1510
|
|
|
@@ -1789,6 +1801,8 @@ export class BridgeRunner {
|
|
|
1789
1801
|
backendName,
|
|
1790
1802
|
resumeSessionId,
|
|
1791
1803
|
daemonName,
|
|
1804
|
+
prePrompt,
|
|
1805
|
+
shouldProcessPrePrompt,
|
|
1792
1806
|
}) {
|
|
1793
1807
|
this.backendSession = backendSession;
|
|
1794
1808
|
this.conductor = conductor;
|
|
@@ -1818,6 +1832,9 @@ export class BridgeRunner {
|
|
|
1818
1832
|
this.initialPromptDelivery === "queued" && typeof initialPrompt === "string" && initialPrompt.trim()
|
|
1819
1833
|
? initialPrompt.trim()
|
|
1820
1834
|
: "";
|
|
1835
|
+
this.prePrompt =
|
|
1836
|
+
typeof prePrompt === "string" && prePrompt.trim() ? prePrompt.trim() : "";
|
|
1837
|
+
this.shouldProcessPrePrompt = Boolean(shouldProcessPrePrompt) && Boolean(this.prePrompt);
|
|
1821
1838
|
this.sessionStreamReplyCounts = new Map();
|
|
1822
1839
|
this.lastRuntimeStatusSignature = null;
|
|
1823
1840
|
this.lastRuntimeStatusPayload = null;
|
|
@@ -2027,6 +2044,17 @@ export class BridgeRunner {
|
|
|
2027
2044
|
return;
|
|
2028
2045
|
}
|
|
2029
2046
|
|
|
2047
|
+
if (this.shouldProcessPrePrompt) {
|
|
2048
|
+
this.copilotLog(
|
|
2049
|
+
`processing pre_prompt via synthetic attach flow contentLen=${this.prePrompt.length}`,
|
|
2050
|
+
);
|
|
2051
|
+
this.shouldProcessPrePrompt = false;
|
|
2052
|
+
await this.handlePrePromptMessage(this.prePrompt);
|
|
2053
|
+
if (this.stopped) {
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2030
2058
|
if (this.initialPrompt && this.initialPromptDelivery === "synthetic") {
|
|
2031
2059
|
this.copilotLog("processing initial prompt via synthetic attach flow");
|
|
2032
2060
|
await this.handleSyntheticMessage(this.initialPrompt, {
|
|
@@ -3049,6 +3077,51 @@ export class BridgeRunner {
|
|
|
3049
3077
|
}
|
|
3050
3078
|
|
|
3051
3079
|
async handleSyntheticMessage(content, { includeImages }) {
|
|
3080
|
+
return this.runSyntheticTurn({
|
|
3081
|
+
content,
|
|
3082
|
+
replyTarget: "initial",
|
|
3083
|
+
includeImages: Boolean(includeImages),
|
|
3084
|
+
logTag: "synthetic",
|
|
3085
|
+
introLabel: "初始提示",
|
|
3086
|
+
errorLabel: "初始提示",
|
|
3087
|
+
});
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
async handlePrePromptMessage(content) {
|
|
3091
|
+
const text = typeof content === "string" ? content.trim() : "";
|
|
3092
|
+
if (!text) {
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
return this.runSyntheticTurn({
|
|
3096
|
+
content: text,
|
|
3097
|
+
replyTarget: "pre_prompt",
|
|
3098
|
+
includeImages: false,
|
|
3099
|
+
logTag: "pre_prompt",
|
|
3100
|
+
introLabel: "pre_prompt",
|
|
3101
|
+
errorLabel: "pre_prompt",
|
|
3102
|
+
surfaceUserMessage: {
|
|
3103
|
+
content: text,
|
|
3104
|
+
metadata: {
|
|
3105
|
+
pre_prompt: true,
|
|
3106
|
+
role: "user",
|
|
3107
|
+
visible_as: "user",
|
|
3108
|
+
origin: "pre_prompt",
|
|
3109
|
+
},
|
|
3110
|
+
},
|
|
3111
|
+
replyMetadata: { pre_prompt_response: true },
|
|
3112
|
+
});
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
async runSyntheticTurn({
|
|
3116
|
+
content,
|
|
3117
|
+
replyTarget,
|
|
3118
|
+
includeImages,
|
|
3119
|
+
logTag,
|
|
3120
|
+
introLabel,
|
|
3121
|
+
errorLabel,
|
|
3122
|
+
surfaceUserMessage,
|
|
3123
|
+
replyMetadata,
|
|
3124
|
+
}) {
|
|
3052
3125
|
this.lastRuntimeStatusSignature = null;
|
|
3053
3126
|
this.runningTurn = true;
|
|
3054
3127
|
const startedAt = Date.now();
|
|
@@ -3056,28 +3129,48 @@ export class BridgeRunner {
|
|
|
3056
3129
|
this.useSessionFileReplyStream &&
|
|
3057
3130
|
typeof this.backendSession?.setSessionReplyTarget === "function"
|
|
3058
3131
|
) {
|
|
3059
|
-
this.backendSession.setSessionReplyTarget(
|
|
3132
|
+
this.backendSession.setSessionReplyTarget(replyTarget);
|
|
3133
|
+
}
|
|
3134
|
+
this.copilotLog(
|
|
3135
|
+
`${logTag} turn start includeImages=${Boolean(includeImages)} contentLen=${String(content || "").length}`,
|
|
3136
|
+
);
|
|
3137
|
+
if (surfaceUserMessage) {
|
|
3138
|
+
try {
|
|
3139
|
+
await this.conductor.sendMessage(this.taskId, surfaceUserMessage.content, {
|
|
3140
|
+
backend: this.backendName,
|
|
3141
|
+
thread_id: this.backendSession?.threadId,
|
|
3142
|
+
cli_args: this.cliArgs,
|
|
3143
|
+
synthetic: true,
|
|
3144
|
+
...(surfaceUserMessage.metadata || {}),
|
|
3145
|
+
});
|
|
3146
|
+
this.copilotLog(
|
|
3147
|
+
`${logTag} message surfaced to task len=${surfaceUserMessage.content.length}`,
|
|
3148
|
+
);
|
|
3149
|
+
} catch (error) {
|
|
3150
|
+
log(`Failed to surface ${logTag} message: ${error?.message || error}`);
|
|
3151
|
+
}
|
|
3060
3152
|
}
|
|
3061
|
-
this.copilotLog(`synthetic turn start includeImages=${Boolean(includeImages)} contentLen=${String(content || "").length}`);
|
|
3062
3153
|
try {
|
|
3063
3154
|
const result = await this.backendSession.runTurn(content, {
|
|
3064
|
-
useInitialImages: includeImages,
|
|
3155
|
+
useInitialImages: Boolean(includeImages),
|
|
3065
3156
|
onProgress: (payload) => {
|
|
3066
|
-
void this.reportRuntimeStatus(payload,
|
|
3157
|
+
void this.reportRuntimeStatus(payload, replyTarget);
|
|
3067
3158
|
},
|
|
3068
3159
|
});
|
|
3069
3160
|
this.copilotLog(
|
|
3070
|
-
|
|
3161
|
+
`${logTag} runTurn completed elapsedMs=${Date.now() - startedAt} answerLen=${String(result.text || "").trim().length}`,
|
|
3071
3162
|
);
|
|
3072
3163
|
if (!this.useSessionFileReplyStream) {
|
|
3073
3164
|
const backendLabel = this.backendName.charAt(0).toUpperCase() + this.backendName.slice(1);
|
|
3074
|
-
const intro = `${backendLabel}
|
|
3165
|
+
const intro = `${backendLabel} 已根据${introLabel}给出回复:`;
|
|
3075
3166
|
const replyText =
|
|
3076
|
-
result.text ||
|
|
3167
|
+
result.text ||
|
|
3168
|
+
extractAgentTextFromItems(result.items) ||
|
|
3169
|
+
extractAgentTextFromMetadata(result.metadata);
|
|
3077
3170
|
const text = replyText ? `${intro}\n\n${replyText}` : intro;
|
|
3078
3171
|
logBackendReply(this.backendName, replyText || "(无文本输出)", {
|
|
3079
3172
|
usage: result.usage,
|
|
3080
|
-
replyTo:
|
|
3173
|
+
replyTo: replyTarget,
|
|
3081
3174
|
});
|
|
3082
3175
|
await this.conductor.sendMessage(this.taskId, text, {
|
|
3083
3176
|
model: this.backendSession.threadOptions?.model || this.backendName,
|
|
@@ -3086,27 +3179,32 @@ export class BridgeRunner {
|
|
|
3086
3179
|
thread_id: this.backendSession.threadId,
|
|
3087
3180
|
cli_args: this.cliArgs,
|
|
3088
3181
|
synthetic: true,
|
|
3182
|
+
...(replyMetadata || {}),
|
|
3089
3183
|
});
|
|
3090
|
-
this.copilotLog(
|
|
3184
|
+
this.copilotLog(`${logTag} sdk_message sent responseLen=${text.length}`);
|
|
3091
3185
|
} else {
|
|
3092
|
-
this.copilotLog(
|
|
3186
|
+
this.copilotLog(`${logTag} session_file turn settled`);
|
|
3093
3187
|
}
|
|
3094
3188
|
await this.syncBackendSessionBinding();
|
|
3095
3189
|
} catch (error) {
|
|
3096
3190
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3097
3191
|
if (this.stopped && (this.remoteStopInfo || isSessionClosedError(error))) {
|
|
3098
|
-
this.copilotLog(
|
|
3192
|
+
this.copilotLog(`${logTag} turn interrupted by stop_task elapsedMs=${Date.now() - startedAt}`);
|
|
3099
3193
|
return;
|
|
3100
3194
|
}
|
|
3101
|
-
if (
|
|
3195
|
+
if (
|
|
3196
|
+
await this.settleCodexCheckpointUnavailableAfterStream(replyTarget, errorMessage, {
|
|
3197
|
+
markProcessed: false,
|
|
3198
|
+
})
|
|
3199
|
+
) {
|
|
3102
3200
|
return;
|
|
3103
3201
|
}
|
|
3104
3202
|
this.copilotLog(
|
|
3105
|
-
|
|
3203
|
+
`${logTag} turn failed elapsedMs=${Date.now() - startedAt} error="${sanitizeForLog(errorMessage, 200)}"`,
|
|
3106
3204
|
);
|
|
3107
|
-
await this.reportError(
|
|
3205
|
+
await this.reportError(`${errorLabel}执行失败: ${errorMessage}`);
|
|
3108
3206
|
} finally {
|
|
3109
|
-
this.copilotLog(
|
|
3207
|
+
this.copilotLog(`${logTag} turn end elapsedMs=${Date.now() - startedAt}`);
|
|
3110
3208
|
this.runningTurn = false;
|
|
3111
3209
|
}
|
|
3112
3210
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@love-moon/conductor-cli",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"gitCommitId": "
|
|
3
|
+
"version": "0.2.42",
|
|
4
|
+
"gitCommitId": "f79f36f",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"conductor": "bin/conductor.js"
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"test": "node --test test/*.test.js"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@love-moon/ai-manager": "0.2.
|
|
21
|
-
"@love-moon/ai-sdk": "0.2.
|
|
22
|
-
"@love-moon/conductor-sdk": "0.2.
|
|
20
|
+
"@love-moon/ai-manager": "0.2.42",
|
|
21
|
+
"@love-moon/ai-sdk": "0.2.42",
|
|
22
|
+
"@love-moon/conductor-sdk": "0.2.42",
|
|
23
23
|
"@github/copilot-sdk": "^0.2.2",
|
|
24
24
|
"chrome-launcher": "^1.2.1",
|
|
25
25
|
"chrome-remote-interface": "^0.33.0",
|