@openclaw/copilot 2026.6.10 → 2026.6.11
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/README.md +1 -1
- package/dist/{attempt-BQoxgpM3.js → attempt-ArBh6GPT.js} +459 -50
- package/dist/{harness-I9ahzRYI.js → harness-D-3KWchY.js} +12 -3
- package/dist/harness.js +1 -1
- package/dist/index.js +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/openclaw.plugin.json +1 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ on a model or provider entry; `auto` never picks it. PI remains the default
|
|
|
16
16
|
embedded runtime.
|
|
17
17
|
|
|
18
18
|
See [GitHub Copilot agent runtime](../../docs/plugins/copilot.md) for
|
|
19
|
-
configuration, doctor
|
|
19
|
+
configuration, the doctor contract, transcript mirroring, compaction, side
|
|
20
20
|
questions, replay, and the supported-surface contract.
|
|
21
21
|
See [qa/copilot-capabilities.md](../../qa/copilot-capabilities.md)
|
|
22
22
|
for the SDK capability inventory the harness is pinned to.
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { n as resolveCopilotAuth } from "./harness-
|
|
2
|
-
import {
|
|
1
|
+
import { n as resolveCopilotAuth } from "./harness-D-3KWchY.js";
|
|
2
|
+
import { applyEmbeddedAttemptToolsAllow, awaitAgentEndSideEffects, buildAgentHarnessUserInputAnswers, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, detectAndLoadAgentHarnessPromptImages, embeddedAgentLog, extractToolErrorMessage, getPluginToolMeta, isSubagentSessionKey, isToolResultError, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptFsWorkspaceOnly, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveCompactionTimeoutMs, resolveEmbeddedAttemptToolConstructionPlan, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, resolveUserPath, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, sanitizeToolResult, setActiveEmbeddedRun } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import fsp from "node:fs/promises";
|
|
6
|
+
import { publishSessionTranscriptUpdateByIdentity, withSessionTranscriptWriteLock } from "openclaw/plugin-sdk/session-transcript-runtime";
|
|
7
|
+
import { createAgentHarnessTaskRuntime } from "openclaw/plugin-sdk/agent-harness-task-runtime";
|
|
8
|
+
import { createAgentHarnessToolSurfaceRuntime } from "openclaw/plugin-sdk/agent-harness-tool-runtime";
|
|
6
9
|
//#region extensions/copilot/src/compaction-bridge.ts
|
|
7
10
|
/**
|
|
8
11
|
* Shape an `InfiniteSessionConfig` for `SessionConfig.infiniteSessions`.
|
|
@@ -95,12 +98,13 @@ function buildMirrorDedupeIdentity(message) {
|
|
|
95
98
|
async function mirrorCopilotTranscript(params) {
|
|
96
99
|
const messages = params.messages.filter((message) => message.role === "user" || message.role === "assistant" || message.role === "toolResult");
|
|
97
100
|
if (messages.length === 0) return;
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
const transcriptTarget = resolveCopilotMirrorTranscriptTarget(params);
|
|
102
|
+
if (await withSessionTranscriptWriteLock({
|
|
103
|
+
...transcriptTarget,
|
|
104
|
+
config: params.config
|
|
105
|
+
}, async (transcript) => {
|
|
106
|
+
let didAppendMessage = false;
|
|
107
|
+
const existingIdempotencyKeys = readTranscriptIdempotencyKeys(await transcript.readEvents());
|
|
104
108
|
for (const message of messages) {
|
|
105
109
|
const dedupeIdentity = buildMirrorDedupeIdentity(message);
|
|
106
110
|
const idempotencyKey = params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0;
|
|
@@ -118,39 +122,35 @@ async function mirrorCopilotTranscript(params) {
|
|
|
118
122
|
...nextMessage,
|
|
119
123
|
idempotencyKey
|
|
120
124
|
} : nextMessage;
|
|
121
|
-
await
|
|
122
|
-
transcriptPath: params.sessionFile,
|
|
125
|
+
if (!await transcript.appendMessage({
|
|
123
126
|
message: messageToAppend,
|
|
124
|
-
|
|
125
|
-
});
|
|
127
|
+
idempotencyLookup: idempotencyKey ? "caller-checked" : "scan"
|
|
128
|
+
})) continue;
|
|
129
|
+
didAppendMessage = true;
|
|
126
130
|
if (idempotencyKey) existingIdempotencyKeys.add(idempotencyKey);
|
|
127
131
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
sessionFile: params.sessionFile,
|
|
133
|
-
sessionKey: params.sessionKey
|
|
132
|
+
return didAppendMessage;
|
|
133
|
+
})) await publishSessionTranscriptUpdateByIdentity({
|
|
134
|
+
...transcriptTarget,
|
|
135
|
+
update: params.sessionKey ? { sessionKey: params.sessionKey } : void 0
|
|
134
136
|
});
|
|
135
|
-
else emitSessionTranscriptUpdate(params.sessionFile);
|
|
136
137
|
}
|
|
137
|
-
|
|
138
|
+
function resolveCopilotMirrorTranscriptTarget(params) {
|
|
139
|
+
const sessionFile = params.sessionFile.trim();
|
|
140
|
+
if (!sessionFile) throw new Error("Copilot transcript mirror requires a sessionFile target");
|
|
141
|
+
return {
|
|
142
|
+
...params.agentId ? { agentId: params.agentId } : {},
|
|
143
|
+
sessionFile,
|
|
144
|
+
sessionId: params.sessionId,
|
|
145
|
+
sessionKey: params.sessionKey ?? ""
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function readTranscriptIdempotencyKeys(events) {
|
|
138
149
|
const keys = /* @__PURE__ */ new Set();
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (error.code !== "ENOENT") throw error;
|
|
144
|
-
return keys;
|
|
145
|
-
}
|
|
146
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
147
|
-
if (!line.trim()) continue;
|
|
148
|
-
try {
|
|
149
|
-
const parsed = JSON.parse(line);
|
|
150
|
-
if (typeof parsed.message?.idempotencyKey === "string") keys.add(parsed.message.idempotencyKey);
|
|
151
|
-
} catch {
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
150
|
+
for (const event of events) {
|
|
151
|
+
if (!event || typeof event !== "object" || Array.isArray(event)) continue;
|
|
152
|
+
const parsed = event;
|
|
153
|
+
if (typeof parsed.message?.idempotencyKey === "string") keys.add(parsed.message.idempotencyKey);
|
|
154
154
|
}
|
|
155
155
|
return keys;
|
|
156
156
|
}
|
|
@@ -229,6 +229,7 @@ function attachEventBridge(session, options) {
|
|
|
229
229
|
let observedCompaction = false;
|
|
230
230
|
let deltaQueue = Promise.resolve();
|
|
231
231
|
let deltaChain = Promise.resolve();
|
|
232
|
+
let agentEventChain = Promise.resolve();
|
|
232
233
|
let compactionChain = Promise.resolve();
|
|
233
234
|
let compactionIdle = Promise.resolve();
|
|
234
235
|
let resolveCompactionIdle;
|
|
@@ -294,6 +295,44 @@ function attachEventBridge(session, options) {
|
|
|
294
295
|
toolName
|
|
295
296
|
});
|
|
296
297
|
});
|
|
298
|
+
registerListener(session, unsubscribeFns, "session.plan_changed", (event) => {
|
|
299
|
+
enqueueAgentEvent({
|
|
300
|
+
stream: "plan",
|
|
301
|
+
data: {
|
|
302
|
+
phase: "update",
|
|
303
|
+
title: "Plan updated",
|
|
304
|
+
source: "copilot-sdk",
|
|
305
|
+
operation: event.data.operation,
|
|
306
|
+
...event.agentId ? { agentId: event.agentId } : {}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
registerListener(session, unsubscribeFns, "exit_plan_mode.requested", (event) => {
|
|
311
|
+
const steps = splitPlanText(event.data.planContent);
|
|
312
|
+
enqueueAgentEvent({
|
|
313
|
+
stream: "plan",
|
|
314
|
+
data: {
|
|
315
|
+
phase: "update",
|
|
316
|
+
title: "Plan updated",
|
|
317
|
+
source: "copilot-sdk",
|
|
318
|
+
...event.data.summary ? { explanation: event.data.summary } : {},
|
|
319
|
+
...steps.length > 0 ? { steps } : {},
|
|
320
|
+
...event.data.actions.length > 0 ? { actions: event.data.actions } : {},
|
|
321
|
+
...event.data.requestId ? { requestId: event.data.requestId } : {},
|
|
322
|
+
...event.data.recommendedAction ? { recommendedAction: event.data.recommendedAction } : {},
|
|
323
|
+
...event.agentId ? { agentId: event.agentId } : {}
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
registerListener(session, unsubscribeFns, "subagent.started", (event) => {
|
|
328
|
+
forwardNativeSubagentEvent(event);
|
|
329
|
+
});
|
|
330
|
+
registerListener(session, unsubscribeFns, "subagent.completed", (event) => {
|
|
331
|
+
forwardNativeSubagentEvent(event);
|
|
332
|
+
});
|
|
333
|
+
registerListener(session, unsubscribeFns, "subagent.failed", (event) => {
|
|
334
|
+
forwardNativeSubagentEvent(event);
|
|
335
|
+
});
|
|
297
336
|
registerListener(session, unsubscribeFns, "session.compaction_start", (event) => {
|
|
298
337
|
if (!isRootCompactionEvent(event)) return;
|
|
299
338
|
observedCompaction = true;
|
|
@@ -350,6 +389,9 @@ function attachEventBridge(session, options) {
|
|
|
350
389
|
awaitDeltaChain() {
|
|
351
390
|
return deltaChain;
|
|
352
391
|
},
|
|
392
|
+
awaitAgentEventChain() {
|
|
393
|
+
return agentEventChain;
|
|
394
|
+
},
|
|
353
395
|
hasObservedCompaction() {
|
|
354
396
|
return observedCompaction;
|
|
355
397
|
},
|
|
@@ -397,6 +439,17 @@ function attachEventBridge(session, options) {
|
|
|
397
439
|
if (!callback) return;
|
|
398
440
|
compactionChain = compactionChain.then(callback, callback).catch(() => void 0);
|
|
399
441
|
}
|
|
442
|
+
function enqueueAgentEvent(event) {
|
|
443
|
+
const callback = options.onAgentEvent;
|
|
444
|
+
if (!callback) return;
|
|
445
|
+
const invoke = () => callback(event);
|
|
446
|
+
agentEventChain = agentEventChain.then(invoke, invoke).catch(() => void 0);
|
|
447
|
+
}
|
|
448
|
+
function forwardNativeSubagentEvent(event) {
|
|
449
|
+
try {
|
|
450
|
+
options.onNativeSubagentEvent?.(event);
|
|
451
|
+
} catch {}
|
|
452
|
+
}
|
|
400
453
|
async function awaitStableCompaction() {
|
|
401
454
|
const idle = activeCompactionCount > 0 ? compactionIdle : void 0;
|
|
402
455
|
if (idle) await idle;
|
|
@@ -473,6 +526,9 @@ function isRootCompactionEvent(event) {
|
|
|
473
526
|
function joinReasoning(order, reasoningById) {
|
|
474
527
|
return order.map((reasoningId) => reasoningById.get(reasoningId) ?? "").join("");
|
|
475
528
|
}
|
|
529
|
+
function splitPlanText(text) {
|
|
530
|
+
return (text ?? "").split(/\r?\n/).map((line) => line.trim().replace(/^[-*]\s+/, "")).filter((line) => line.length > 0);
|
|
531
|
+
}
|
|
476
532
|
function readString$2(value) {
|
|
477
533
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
478
534
|
}
|
|
@@ -561,6 +617,130 @@ function createHooksBridge(config, options) {
|
|
|
561
617
|
return Object.keys(hooks).length > 0 ? hooks : void 0;
|
|
562
618
|
}
|
|
563
619
|
//#endregion
|
|
620
|
+
//#region extensions/copilot/src/native-subagent-task-mirror.ts
|
|
621
|
+
const COPILOT_NATIVE_SUBAGENT_TASK_KIND = "copilot-native";
|
|
622
|
+
const COPILOT_NATIVE_SUBAGENT_RUN_ID_PREFIX = "copilot-agent:";
|
|
623
|
+
function createCopilotNativeSubagentTaskMirror(params) {
|
|
624
|
+
if (!params.scope) return;
|
|
625
|
+
return new CopilotNativeSubagentTaskMirror({
|
|
626
|
+
agentId: params.agentId,
|
|
627
|
+
now: params.now
|
|
628
|
+
}, createAgentHarnessTaskRuntime({
|
|
629
|
+
runtime: "subagent",
|
|
630
|
+
taskKind: COPILOT_NATIVE_SUBAGENT_TASK_KIND,
|
|
631
|
+
scope: params.scope,
|
|
632
|
+
runIdPrefix: COPILOT_NATIVE_SUBAGENT_RUN_ID_PREFIX
|
|
633
|
+
}));
|
|
634
|
+
}
|
|
635
|
+
var CopilotNativeSubagentTaskMirror = class {
|
|
636
|
+
constructor(params, runtime) {
|
|
637
|
+
this.params = params;
|
|
638
|
+
this.runtime = runtime;
|
|
639
|
+
this.runIdByAgentId = /* @__PURE__ */ new Map();
|
|
640
|
+
this.runIdByToolCallId = /* @__PURE__ */ new Map();
|
|
641
|
+
this.terminalRunIds = /* @__PURE__ */ new Set();
|
|
642
|
+
this.activeRunIds = /* @__PURE__ */ new Set();
|
|
643
|
+
this.now = params.now ?? Date.now;
|
|
644
|
+
}
|
|
645
|
+
handleEvent(event) {
|
|
646
|
+
const toolCallId = event.data.toolCallId.trim();
|
|
647
|
+
if (!toolCallId) return;
|
|
648
|
+
const runId = this.resolveRunId(event);
|
|
649
|
+
if (event.type === "subagent.started") {
|
|
650
|
+
this.handleStarted(event, runId, toolCallId);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (event.type === "subagent.completed") {
|
|
654
|
+
this.handleCompleted(event, runId);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
this.handleFailed(event, runId);
|
|
658
|
+
}
|
|
659
|
+
finalizeActiveRuns() {
|
|
660
|
+
const eventAt = this.now();
|
|
661
|
+
for (const runId of this.activeRunIds) {
|
|
662
|
+
this.terminalRunIds.add(runId);
|
|
663
|
+
this.runtime.finalizeTaskRunByRunId({
|
|
664
|
+
runId,
|
|
665
|
+
status: "cancelled",
|
|
666
|
+
endedAt: eventAt,
|
|
667
|
+
lastEventAt: eventAt,
|
|
668
|
+
error: "Copilot native subagent ended with its parent attempt.",
|
|
669
|
+
progressSummary: "Copilot native subagent cancelled with its parent attempt.",
|
|
670
|
+
terminalSummary: "Copilot native subagent cancelled."
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
this.activeRunIds.clear();
|
|
674
|
+
}
|
|
675
|
+
handleStarted(event, runId, toolCallId) {
|
|
676
|
+
const agentId = event.agentId?.trim();
|
|
677
|
+
if (agentId ? this.runIdByAgentId.get(agentId) : this.runIdByToolCallId.get(toolCallId)) return;
|
|
678
|
+
const eventAt = this.now();
|
|
679
|
+
const label = event.data.agentDisplayName.trim() || event.data.agentName.trim();
|
|
680
|
+
const task = event.data.agentDescription.trim() || `Copilot native subagent ${label}`;
|
|
681
|
+
if (!this.runtime.tryCreateRunningTaskRun({
|
|
682
|
+
sourceId: toolCallId,
|
|
683
|
+
agentId: this.params.agentId,
|
|
684
|
+
runId,
|
|
685
|
+
label: label || "Copilot subagent",
|
|
686
|
+
task,
|
|
687
|
+
notifyPolicy: "silent",
|
|
688
|
+
deliveryStatus: "not_applicable",
|
|
689
|
+
preferMetadata: true,
|
|
690
|
+
startedAt: eventAt,
|
|
691
|
+
lastEventAt: eventAt,
|
|
692
|
+
progressSummary: "Copilot native subagent started."
|
|
693
|
+
})) return;
|
|
694
|
+
if (agentId) this.runIdByAgentId.set(agentId, runId);
|
|
695
|
+
else this.runIdByToolCallId.set(toolCallId, runId);
|
|
696
|
+
this.terminalRunIds.delete(runId);
|
|
697
|
+
this.activeRunIds.add(runId);
|
|
698
|
+
}
|
|
699
|
+
handleCompleted(event, runId) {
|
|
700
|
+
if (this.terminalRunIds.has(runId)) return;
|
|
701
|
+
const eventAt = this.now();
|
|
702
|
+
this.terminalRunIds.add(runId);
|
|
703
|
+
this.activeRunIds.delete(runId);
|
|
704
|
+
this.runtime.finalizeTaskRunByRunId({
|
|
705
|
+
runId,
|
|
706
|
+
status: "succeeded",
|
|
707
|
+
endedAt: eventAt,
|
|
708
|
+
lastEventAt: eventAt,
|
|
709
|
+
progressSummary: "Copilot native subagent completed.",
|
|
710
|
+
terminalSummary: buildCompletionSummary(event)
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
handleFailed(event, runId) {
|
|
714
|
+
if (this.terminalRunIds.has(runId)) return;
|
|
715
|
+
const eventAt = this.now();
|
|
716
|
+
this.terminalRunIds.add(runId);
|
|
717
|
+
this.activeRunIds.delete(runId);
|
|
718
|
+
this.runtime.finalizeTaskRunByRunId({
|
|
719
|
+
runId,
|
|
720
|
+
status: "failed",
|
|
721
|
+
endedAt: eventAt,
|
|
722
|
+
lastEventAt: eventAt,
|
|
723
|
+
error: event.data.error,
|
|
724
|
+
progressSummary: "Copilot native subagent failed.",
|
|
725
|
+
terminalSummary: "Copilot native subagent failed."
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
resolveRunId(event) {
|
|
729
|
+
const agentId = event.agentId?.trim();
|
|
730
|
+
if (agentId) {
|
|
731
|
+
const existing = this.runIdByAgentId.get(agentId);
|
|
732
|
+
if (existing) return existing;
|
|
733
|
+
}
|
|
734
|
+
const existing = this.runIdByToolCallId.get(event.data.toolCallId);
|
|
735
|
+
if (existing) return existing;
|
|
736
|
+
return `${COPILOT_NATIVE_SUBAGENT_RUN_ID_PREFIX}${agentId || event.data.toolCallId.trim()}`;
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
function buildCompletionSummary(event) {
|
|
740
|
+
const details = [event.data.totalToolCalls !== void 0 ? `${event.data.totalToolCalls} tool calls` : void 0, event.data.totalTokens !== void 0 ? `${event.data.totalTokens} tokens` : void 0].filter((value) => value !== void 0);
|
|
741
|
+
return details.length > 0 ? `Copilot native subagent completed (${details.join(", ")}).` : "Copilot native subagent completed.";
|
|
742
|
+
}
|
|
743
|
+
//#endregion
|
|
564
744
|
//#region extensions/copilot/src/permission-bridge.ts
|
|
565
745
|
/** Built-in fail-closed default. Mirrors the pre-bridge attempt.ts stub. */
|
|
566
746
|
const REJECT_ALL_FEEDBACK = "copilot agent runtime: no permission policy installed (fail-closed default)";
|
|
@@ -812,7 +992,27 @@ async function createCopilotToolBridge(input) {
|
|
|
812
992
|
sourceTools: []
|
|
813
993
|
};
|
|
814
994
|
const createOpenClawCodingTools = input.createOpenClawCodingTools ?? (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
|
|
815
|
-
const
|
|
995
|
+
const toolSurfaceRuntime = createAgentHarnessToolSurfaceRuntime({
|
|
996
|
+
abortSignal: input.abortSignal,
|
|
997
|
+
agentId: input.agentId,
|
|
998
|
+
config: attemptParams.config,
|
|
999
|
+
disableTools: attemptParams.disableTools,
|
|
1000
|
+
executeTool: (toolParams) => executeCatalogTool(input, toolParams),
|
|
1001
|
+
forceMessageTool: shouldForceCopilotMessageTool(attemptParams),
|
|
1002
|
+
isRawModelRun: isCopilotRawModelRun(attemptParams),
|
|
1003
|
+
modelToolsEnabled: true,
|
|
1004
|
+
prompt: attemptParams.prompt,
|
|
1005
|
+
runId: attemptParams.runId,
|
|
1006
|
+
runtimeToolAllowlist: effectiveToolPlan.runtimeToolAllowlist,
|
|
1007
|
+
sessionId: input.sessionId,
|
|
1008
|
+
sessionKey: attemptParams.sandboxSessionKey ?? attemptParams.sessionKey ?? input.sessionKey,
|
|
1009
|
+
sourceReplyDeliveryMode: attemptParams.sourceReplyDeliveryMode,
|
|
1010
|
+
toolsAllow: attemptParams.toolsAllow
|
|
1011
|
+
});
|
|
1012
|
+
const toolOptions = buildOpenClawCodingToolsOptions(input, {
|
|
1013
|
+
...effectiveToolPlan,
|
|
1014
|
+
runtimeToolAllowlist: toolSurfaceRuntime.runtimeToolAllowlist
|
|
1015
|
+
}, toolSurfaceRuntime);
|
|
816
1016
|
let sourceTools;
|
|
817
1017
|
try {
|
|
818
1018
|
sourceTools = await createOpenClawCodingTools(toolOptions);
|
|
@@ -820,10 +1020,12 @@ async function createCopilotToolBridge(input) {
|
|
|
820
1020
|
throw createError(`[copilot-tool-bridge] createOpenClawCodingTools failed: ${toError$1(error).message}`, error);
|
|
821
1021
|
}
|
|
822
1022
|
if (!Array.isArray(sourceTools)) throw new Error("[copilot-tool-bridge] createOpenClawCodingTools must return an array of tools");
|
|
823
|
-
const
|
|
1023
|
+
const allowedSourceTools = filterCopilotToolsForAllowlist(sourceTools, toolSurfaceRuntime.runtimeToolAllowlist);
|
|
1024
|
+
const filteredTools = filterCopilotToolsForAllowlist(filterCopilotToolsForConstructionPlan(toolSurfaceRuntime.compactTools(allowedSourceTools).tools, effectiveToolPlan.codingToolConstructionPlan, { preserveToolNames: toolSurfaceRuntime.runtimeToolAllowlist }), toolSurfaceRuntime.runtimeToolAllowlist);
|
|
824
1025
|
const duplicateNames = findDuplicateToolNames(filteredTools);
|
|
825
1026
|
if (duplicateNames.length > 0) throw new Error(`[copilot-tool-bridge] duplicate tool names: ${duplicateNames.join(", ")}`);
|
|
826
1027
|
return {
|
|
1028
|
+
cleanup: toolSurfaceRuntime.cleanup,
|
|
827
1029
|
sdkTools: filteredTools.map((sourceTool) => convertOpenClawToolToSdkTool(sourceTool, {
|
|
828
1030
|
abortSignal: input.abortSignal,
|
|
829
1031
|
beforeExecute: input.beforeExecute,
|
|
@@ -855,7 +1057,7 @@ async function createCopilotToolBridge(input) {
|
|
|
855
1057
|
* {@link CopilotToolBridgeInput}; callers resolve it via
|
|
856
1058
|
* `resolveSandboxContext` before constructing the bridge.
|
|
857
1059
|
*/
|
|
858
|
-
function buildOpenClawCodingToolsOptions(input, toolPlan) {
|
|
1060
|
+
function buildOpenClawCodingToolsOptions(input, toolPlan, toolSurfaceRuntime) {
|
|
859
1061
|
const a = input.attemptParams ?? {};
|
|
860
1062
|
const sandboxSessionKey = a.sandboxSessionKey?.trim() || a.sessionKey?.trim() || input.sessionKey || input.sessionId;
|
|
861
1063
|
const liveSessionKey = a.sessionKey ?? input.sessionKey;
|
|
@@ -907,11 +1109,14 @@ function buildOpenClawCodingToolsOptions(input, toolPlan) {
|
|
|
907
1109
|
cwd,
|
|
908
1110
|
sandbox,
|
|
909
1111
|
spawnWorkspaceDir,
|
|
910
|
-
config: a.config,
|
|
1112
|
+
config: toolSurfaceRuntime?.config ?? a.config,
|
|
911
1113
|
abortSignal: input.abortSignal,
|
|
912
1114
|
modelProvider: input.modelProvider,
|
|
913
1115
|
modelId: input.modelId,
|
|
914
1116
|
includeCoreTools: toolPlan.includeCoreTools,
|
|
1117
|
+
includeToolSearchControls: toolSurfaceRuntime?.includeToolSearchControls,
|
|
1118
|
+
toolSearchCatalogRef: toolSurfaceRuntime?.toolSearchCatalogRef,
|
|
1119
|
+
toolSearchCatalogExecutor: toolSurfaceRuntime?.toolSearchCatalogExecutor,
|
|
915
1120
|
runtimeToolAllowlist: toolPlan.runtimeToolAllowlist,
|
|
916
1121
|
toolConstructionPlan: toolPlan.codingToolConstructionPlan,
|
|
917
1122
|
modelCompat,
|
|
@@ -1046,6 +1251,56 @@ function convertOpenClawToolToSdkTool(sourceTool, ctx) {
|
|
|
1046
1251
|
skipPermission: true
|
|
1047
1252
|
};
|
|
1048
1253
|
}
|
|
1254
|
+
async function executeCatalogTool(input, params) {
|
|
1255
|
+
const sourceTool = params.tool;
|
|
1256
|
+
const startedAt = Date.now();
|
|
1257
|
+
let preparedArgs = params.input;
|
|
1258
|
+
try {
|
|
1259
|
+
preparedArgs = sourceTool.prepareArguments ? sourceTool.prepareArguments(params.input) : params.input;
|
|
1260
|
+
const result = await sourceTool.execute(params.toolCallId, preparedArgs, params.signal ?? input.abortSignal, params.onUpdate);
|
|
1261
|
+
const sanitizedResult = sanitizeToolResult(result);
|
|
1262
|
+
const isError = isToolResultError(sanitizedResult);
|
|
1263
|
+
input.attemptParams?.onAgentToolResult?.({
|
|
1264
|
+
toolName: params.toolName,
|
|
1265
|
+
result: sanitizedResult,
|
|
1266
|
+
isError
|
|
1267
|
+
});
|
|
1268
|
+
await input.onToolCompleted?.({
|
|
1269
|
+
toolName: params.toolName,
|
|
1270
|
+
toolCallId: params.toolCallId,
|
|
1271
|
+
args: toToolStartArgs(preparedArgs),
|
|
1272
|
+
result: sanitizedResult,
|
|
1273
|
+
...isError ? { error: extractToolErrorMessage(sanitizedResult) ?? "tool returned an error" } : {},
|
|
1274
|
+
startedAt
|
|
1275
|
+
});
|
|
1276
|
+
return result;
|
|
1277
|
+
} catch (error) {
|
|
1278
|
+
const message = toError$1(error).message;
|
|
1279
|
+
const failure = sanitizeToolResult({
|
|
1280
|
+
content: [{
|
|
1281
|
+
type: "text",
|
|
1282
|
+
text: message
|
|
1283
|
+
}],
|
|
1284
|
+
details: {
|
|
1285
|
+
status: "failed",
|
|
1286
|
+
error: message
|
|
1287
|
+
}
|
|
1288
|
+
});
|
|
1289
|
+
input.attemptParams?.onAgentToolResult?.({
|
|
1290
|
+
toolName: params.toolName,
|
|
1291
|
+
result: failure,
|
|
1292
|
+
isError: true
|
|
1293
|
+
});
|
|
1294
|
+
await input.onToolCompleted?.({
|
|
1295
|
+
toolName: params.toolName,
|
|
1296
|
+
toolCallId: params.toolCallId,
|
|
1297
|
+
args: toToolStartArgs(preparedArgs),
|
|
1298
|
+
error: message,
|
|
1299
|
+
startedAt
|
|
1300
|
+
});
|
|
1301
|
+
throw error;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1049
1304
|
function toToolStartArgs(args) {
|
|
1050
1305
|
return args && typeof args === "object" && !Array.isArray(args) ? args : { value: args };
|
|
1051
1306
|
}
|
|
@@ -1139,9 +1394,11 @@ function shouldForceCopilotMessageTool(params) {
|
|
|
1139
1394
|
function filterCopilotToolsForAllowlist(tools, toolsAllow) {
|
|
1140
1395
|
return applyEmbeddedAttemptToolsAllow(tools, toolsAllow, { toolMeta: (tool) => getPluginToolMeta(tool) ?? readInlinePluginToolMeta(tool) });
|
|
1141
1396
|
}
|
|
1142
|
-
function filterCopilotToolsForConstructionPlan(tools, plan) {
|
|
1397
|
+
function filterCopilotToolsForConstructionPlan(tools, plan, options = {}) {
|
|
1143
1398
|
if (plan.includeBaseCodingTools && plan.includeShellTools) return tools;
|
|
1399
|
+
const preserveToolNames = new Set(options.preserveToolNames);
|
|
1144
1400
|
return tools.filter((tool) => {
|
|
1401
|
+
if (preserveToolNames.has(tool.name)) return true;
|
|
1145
1402
|
if (!plan.includeBaseCodingTools && BASE_COPILOT_CODING_TOOL_NAMES.has(tool.name)) return false;
|
|
1146
1403
|
if (!plan.includeShellTools && SHELL_COPILOT_CODING_TOOL_NAMES.has(tool.name)) return false;
|
|
1147
1404
|
return true;
|
|
@@ -1173,6 +1430,97 @@ function toError$1(error) {
|
|
|
1173
1430
|
return error instanceof Error ? error : new Error(String(error));
|
|
1174
1431
|
}
|
|
1175
1432
|
//#endregion
|
|
1433
|
+
//#region extensions/copilot/src/user-input-bridge.ts
|
|
1434
|
+
const COPILOT_USER_INPUT_QUESTION_ID = "answer";
|
|
1435
|
+
function createCopilotUserInputBridge(params) {
|
|
1436
|
+
let pending;
|
|
1437
|
+
const resolvePending = (value) => {
|
|
1438
|
+
const current = pending;
|
|
1439
|
+
if (!current) return;
|
|
1440
|
+
pending = void 0;
|
|
1441
|
+
current.cleanup();
|
|
1442
|
+
current.resolve(value);
|
|
1443
|
+
};
|
|
1444
|
+
return {
|
|
1445
|
+
onUserInputRequest(request) {
|
|
1446
|
+
const question = toQuestion(request);
|
|
1447
|
+
resolvePending(emptyCopilotUserInputResponse());
|
|
1448
|
+
return new Promise((resolve) => {
|
|
1449
|
+
const abortListener = () => resolvePending(emptyCopilotUserInputResponse());
|
|
1450
|
+
const cleanup = () => params.signal?.removeEventListener("abort", abortListener);
|
|
1451
|
+
pending = {
|
|
1452
|
+
question,
|
|
1453
|
+
resolve,
|
|
1454
|
+
cleanup
|
|
1455
|
+
};
|
|
1456
|
+
params.signal?.addEventListener("abort", abortListener, { once: true });
|
|
1457
|
+
if (params.signal?.aborted) {
|
|
1458
|
+
resolvePending(emptyCopilotUserInputResponse());
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
deliverAgentHarnessUserInputPrompt(params.paramsForRun, [question], {
|
|
1462
|
+
intro: "Copilot needs input:",
|
|
1463
|
+
formatText: formatCopilotDisplayText
|
|
1464
|
+
}).catch((error) => {
|
|
1465
|
+
embeddedAgentLog.warn("failed to deliver copilot user input prompt", { error });
|
|
1466
|
+
});
|
|
1467
|
+
});
|
|
1468
|
+
},
|
|
1469
|
+
handleQueuedMessage(text) {
|
|
1470
|
+
const current = pending;
|
|
1471
|
+
if (!current) return false;
|
|
1472
|
+
resolvePending(buildCopilotUserInputResponse(current.question, text));
|
|
1473
|
+
return true;
|
|
1474
|
+
},
|
|
1475
|
+
cancelPending() {
|
|
1476
|
+
resolvePending(emptyCopilotUserInputResponse());
|
|
1477
|
+
}
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
function toQuestion(request) {
|
|
1481
|
+
return {
|
|
1482
|
+
id: COPILOT_USER_INPUT_QUESTION_ID,
|
|
1483
|
+
header: "Copilot needs input",
|
|
1484
|
+
question: request.question,
|
|
1485
|
+
isOther: request.allowFreeform !== false,
|
|
1486
|
+
isSecret: false,
|
|
1487
|
+
options: request.choices && request.choices.length > 0 ? request.choices.map((choice) => ({ label: choice })) : null
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
function buildCopilotUserInputResponse(question, inputText) {
|
|
1491
|
+
const selected = buildAgentHarnessUserInputAnswers([question], inputText).answers[COPILOT_USER_INPUT_QUESTION_ID]?.answers[0] ?? "";
|
|
1492
|
+
return {
|
|
1493
|
+
answer: selected,
|
|
1494
|
+
wasFreeform: !isChoiceAnswer(question, selected)
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
function emptyCopilotUserInputResponse() {
|
|
1498
|
+
return {
|
|
1499
|
+
answer: "",
|
|
1500
|
+
wasFreeform: true
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
function isChoiceAnswer(question, answer) {
|
|
1504
|
+
return Boolean(answer && question.options?.some((option) => option.label.toLowerCase() === answer.toLowerCase()));
|
|
1505
|
+
}
|
|
1506
|
+
function formatCopilotDisplayText(value) {
|
|
1507
|
+
return escapeCopilotChatText(sanitizeCopilotDisplayText(value).trim() || "<unknown>");
|
|
1508
|
+
}
|
|
1509
|
+
function sanitizeCopilotDisplayText(value) {
|
|
1510
|
+
let safe = "";
|
|
1511
|
+
for (const character of value) {
|
|
1512
|
+
const codePoint = character.codePointAt(0);
|
|
1513
|
+
safe += codePoint != null && isUnsafeDisplayCodePoint(codePoint) ? "?" : character;
|
|
1514
|
+
}
|
|
1515
|
+
return safe;
|
|
1516
|
+
}
|
|
1517
|
+
function escapeCopilotChatText(value) {
|
|
1518
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("@", "@").replaceAll("`", "`").replaceAll("[", "[").replaceAll("]", "]").replaceAll("(", "(").replaceAll(")", ")").replaceAll("*", "∗").replaceAll("_", "_").replaceAll("~", "~").replaceAll("|", "|");
|
|
1519
|
+
}
|
|
1520
|
+
function isUnsafeDisplayCodePoint(codePoint) {
|
|
1521
|
+
return codePoint <= 31 || codePoint >= 127 && codePoint <= 159 || codePoint === 173 || codePoint === 1564 || codePoint === 6158 || codePoint >= 8203 && codePoint <= 8207 || codePoint >= 8234 && codePoint <= 8238 || codePoint >= 8288 && codePoint <= 8303 || codePoint === 65279 || codePoint >= 65529 && codePoint <= 65531 || codePoint >= 917504 && codePoint <= 917631;
|
|
1522
|
+
}
|
|
1523
|
+
//#endregion
|
|
1176
1524
|
//#region extensions/copilot/src/workspace-bootstrap.ts
|
|
1177
1525
|
const COPILOT_NATIVE_PROJECT_DOC_BASENAMES = new Set(["agents.md"]);
|
|
1178
1526
|
const COPILOT_BOOTSTRAP_CONTEXT_ORDER = new Map([
|
|
@@ -1325,6 +1673,7 @@ function readResolvedWorkspacePath(value) {
|
|
|
1325
1673
|
//#region extensions/copilot/src/attempt.ts
|
|
1326
1674
|
const SUPPORTED_PROVIDERS = new Set(["github-copilot"]);
|
|
1327
1675
|
const BACKGROUND_COMPACTION_CANCEL_TIMEOUT_MS = 5e3;
|
|
1676
|
+
const COPILOT_ASK_USER_AVAILABLE_TOOLS = ["builtin:ask_user"];
|
|
1328
1677
|
async function runCopilotAgentEndHook(params, hookParams) {
|
|
1329
1678
|
if (!params.messageChannel && !params.messageProvider) {
|
|
1330
1679
|
await awaitAgentEndSideEffects(hookParams);
|
|
@@ -1380,10 +1729,12 @@ function deferBackgroundCompactionCleanup(params) {
|
|
|
1380
1729
|
await cancelBackgroundCompactionBeforeTeardown(params.session);
|
|
1381
1730
|
params.bridge.settleCompactionWait();
|
|
1382
1731
|
}
|
|
1732
|
+
params.finalizeNativeSubagents?.();
|
|
1383
1733
|
params.bridge.detach();
|
|
1384
1734
|
try {
|
|
1385
1735
|
await params.session.disconnect();
|
|
1386
1736
|
} catch {}
|
|
1737
|
+
params.cleanupToolBridge?.();
|
|
1387
1738
|
if (outcome !== "completed" && params.sdkSessionId) try {
|
|
1388
1739
|
await params.handle.client.deleteSession(params.sdkSessionId);
|
|
1389
1740
|
} catch {}
|
|
@@ -1482,17 +1833,31 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1482
1833
|
let handle;
|
|
1483
1834
|
let session;
|
|
1484
1835
|
let bridge;
|
|
1836
|
+
const nativeSubagentTaskMirror = createCopilotNativeSubagentTaskMirror({
|
|
1837
|
+
agentId: sessionAgentId,
|
|
1838
|
+
now,
|
|
1839
|
+
scope: input.agentHarnessTaskRuntimeScope
|
|
1840
|
+
});
|
|
1841
|
+
let activeRunHandleRef;
|
|
1842
|
+
let userInputBridgeRef;
|
|
1843
|
+
let cleanupToolBridge;
|
|
1485
1844
|
let releaseError;
|
|
1486
1845
|
let downgradedFromResume = false;
|
|
1487
1846
|
let resumeFailureRecovered = false;
|
|
1488
1847
|
let yieldDetected = false;
|
|
1489
|
-
const
|
|
1848
|
+
const markExternalAbort = () => {
|
|
1490
1849
|
abortRequested = true;
|
|
1491
1850
|
externalAbort = true;
|
|
1492
1851
|
aborted = true;
|
|
1852
|
+
};
|
|
1853
|
+
const abortActiveSession = () => {
|
|
1854
|
+
markExternalAbort();
|
|
1493
1855
|
if (settled || !sentTurnStarted || !session) return;
|
|
1494
1856
|
session.abort().catch(() => void 0);
|
|
1495
1857
|
};
|
|
1858
|
+
const onAbort = () => {
|
|
1859
|
+
abortActiveSession();
|
|
1860
|
+
};
|
|
1496
1861
|
params.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
1497
1862
|
const resolveSandbox = deps.resolveSandboxContextOverride ?? resolveSandboxContext;
|
|
1498
1863
|
let sandbox = null;
|
|
@@ -1552,7 +1917,7 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1552
1917
|
try {
|
|
1553
1918
|
let sdkTools;
|
|
1554
1919
|
try {
|
|
1555
|
-
|
|
1920
|
+
const toolBridge = await createToolBridge({
|
|
1556
1921
|
modelProvider: modelRef.provider,
|
|
1557
1922
|
modelId: modelRef.id,
|
|
1558
1923
|
agentId: readString(params.agentId) ?? "copilot",
|
|
@@ -1582,7 +1947,9 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1582
1947
|
...error ? { error } : {},
|
|
1583
1948
|
startedAt
|
|
1584
1949
|
})
|
|
1585
|
-
})
|
|
1950
|
+
});
|
|
1951
|
+
cleanupToolBridge = toolBridge.cleanup;
|
|
1952
|
+
sdkTools = toolBridge.sdkTools;
|
|
1586
1953
|
} catch (error) {
|
|
1587
1954
|
return finishAttempt(createResult(input, {
|
|
1588
1955
|
messagesSnapshot: messages,
|
|
@@ -1631,7 +1998,12 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1631
1998
|
});
|
|
1632
1999
|
};
|
|
1633
2000
|
const hasNativePromptHook = Boolean(attemptInput.hooksConfig?.onUserPromptSubmitted);
|
|
1634
|
-
const
|
|
2001
|
+
const userInputBridge = createCopilotUserInputBridge({
|
|
2002
|
+
paramsForRun: attemptInput,
|
|
2003
|
+
signal: params.abortSignal
|
|
2004
|
+
});
|
|
2005
|
+
userInputBridgeRef = userInputBridge;
|
|
2006
|
+
const sessionConfig = createSessionConfig(attemptInput, modelRef.id, sdkTools, poolAcquire.auth, promptBuild.developerInstructions || void 0, effectiveWorkspaceDir, effectiveCwd, userInputBridge.onUserInputRequest, hasNativePromptHook ? { onUserPromptSubmitted: ({ additionalContext, prompt }) => emitLlmInput(prompt, additionalContext) } : void 0);
|
|
1635
2007
|
const replayDecision = decideReplayAction({
|
|
1636
2008
|
sdkSessionId: input.initialReplayState?.sdkSessionId,
|
|
1637
2009
|
replayInvalid: input.initialReplayState?.replayInvalid
|
|
@@ -1661,6 +2033,8 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1661
2033
|
} catch {}
|
|
1662
2034
|
bridge = attachEventBridge(session, {
|
|
1663
2035
|
onAssistantDelta: input.onAssistantDelta,
|
|
2036
|
+
onAgentEvent: input.onAgentEvent,
|
|
2037
|
+
onNativeSubagentEvent: (event) => nativeSubagentTaskMirror?.handleEvent(event),
|
|
1664
2038
|
onCompactionStart: async () => {
|
|
1665
2039
|
const sessionFile = readString(input.sessionFile);
|
|
1666
2040
|
if (!sessionFile) return;
|
|
@@ -1681,6 +2055,26 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1681
2055
|
getSdkSessionId: () => sdkSessionId,
|
|
1682
2056
|
isAborted: () => aborted
|
|
1683
2057
|
});
|
|
2058
|
+
const activeRunHandle = {
|
|
2059
|
+
kind: "embedded",
|
|
2060
|
+
queueMessage: async (text) => {
|
|
2061
|
+
if (userInputBridge.handleQueuedMessage(text)) return;
|
|
2062
|
+
throw new Error("Copilot runtime is not waiting for user input.");
|
|
2063
|
+
},
|
|
2064
|
+
isStreaming: () => !settled && !aborted,
|
|
2065
|
+
isCompacting: () => bridge?.isCompacting() ?? false,
|
|
2066
|
+
sourceReplyDeliveryMode: input.sourceReplyDeliveryMode,
|
|
2067
|
+
cancel: () => {
|
|
2068
|
+
userInputBridge.cancelPending();
|
|
2069
|
+
abortActiveSession();
|
|
2070
|
+
},
|
|
2071
|
+
abort: () => {
|
|
2072
|
+
userInputBridge.cancelPending();
|
|
2073
|
+
abortActiveSession();
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2076
|
+
setActiveEmbeddedRun(input.sessionId, activeRunHandle, input.sessionKey, input.sessionFile);
|
|
2077
|
+
activeRunHandleRef = activeRunHandle;
|
|
1684
2078
|
const messageOptions = await createMessageOptions(attemptInput, {
|
|
1685
2079
|
effectiveCwd,
|
|
1686
2080
|
effectiveWorkspaceDir,
|
|
@@ -1696,6 +2090,7 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1696
2090
|
if (!hasNativePromptHook) emitLlmInput(attemptInput.prompt);
|
|
1697
2091
|
const result = await session.sendAndWait(messageOptions, input.timeoutMs);
|
|
1698
2092
|
await bridge.awaitDeltaChain();
|
|
2093
|
+
await bridge.awaitAgentEventChain();
|
|
1699
2094
|
if (!bridge.recordSendResult(result) && !aborted) {
|
|
1700
2095
|
timedOut = true;
|
|
1701
2096
|
timedOutDuringCompaction = bridge.isCompacting();
|
|
@@ -1710,9 +2105,12 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1710
2105
|
try {
|
|
1711
2106
|
await bridge?.awaitDeltaChain();
|
|
1712
2107
|
} catch {}
|
|
2108
|
+
await bridge?.awaitAgentEventChain();
|
|
1713
2109
|
} else promptError = toError(error);
|
|
1714
2110
|
} finally {
|
|
1715
2111
|
settled = true;
|
|
2112
|
+
userInputBridgeRef?.cancelPending();
|
|
2113
|
+
if (activeRunHandleRef) clearActiveEmbeddedRun(input.sessionId, activeRunHandleRef, input.sessionKey, input.sessionFile);
|
|
1716
2114
|
if ((bridge?.hasObservedCompaction() || timedOut && bridge?.hasObservedSessionIdle() === false) && bridge && session && handle) {
|
|
1717
2115
|
const cleanupAbort = new AbortController();
|
|
1718
2116
|
const abortCleanup = () => cleanupAbort.abort();
|
|
@@ -1722,6 +2120,8 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1722
2120
|
abortSignal: cleanupAbort.signal,
|
|
1723
2121
|
awaitSessionIdle: !bridge.hasObservedSessionIdle(),
|
|
1724
2122
|
bridge,
|
|
2123
|
+
cleanupToolBridge,
|
|
2124
|
+
finalizeNativeSubagents: () => nativeSubagentTaskMirror?.finalizeActiveRuns(),
|
|
1725
2125
|
handle,
|
|
1726
2126
|
pool: deps.pool,
|
|
1727
2127
|
sdkSessionId,
|
|
@@ -1741,6 +2141,9 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1741
2141
|
params.abortSignal?.removeEventListener("abort", onAbort);
|
|
1742
2142
|
} else {
|
|
1743
2143
|
await bridge?.awaitCompactionChain();
|
|
2144
|
+
await bridge?.awaitAgentEventChain();
|
|
2145
|
+
nativeSubagentTaskMirror?.finalizeActiveRuns();
|
|
2146
|
+
cleanupToolBridge?.();
|
|
1744
2147
|
bridge?.detach();
|
|
1745
2148
|
params.abortSignal?.removeEventListener("abort", onAbort);
|
|
1746
2149
|
if (session) try {
|
|
@@ -1778,19 +2181,21 @@ async function runCopilotAttempt(params, deps) {
|
|
|
1778
2181
|
...taggedLastAssistant ? [taggedLastAssistant] : []
|
|
1779
2182
|
];
|
|
1780
2183
|
const sessionFileForMirror = readString(input.sessionFile);
|
|
1781
|
-
const
|
|
1782
|
-
|
|
2184
|
+
const openClawSessionIdForMirror = readString(input.sessionId);
|
|
2185
|
+
const mirrorScopeSessionId = sessionIdUsed ?? openClawSessionIdForMirror;
|
|
2186
|
+
if (sessionFileForMirror && openClawSessionIdForMirror && messagesSnapshot.length > 0) {
|
|
1783
2187
|
const taggedMessages = messagesSnapshot.map((message, index) => {
|
|
1784
2188
|
if (message.role !== "user" && message.role !== "assistant" && message.role !== "toolResult") return message;
|
|
1785
2189
|
if (hasMirrorIdentity(message)) return message;
|
|
1786
|
-
return attachCopilotMirrorIdentity(message, `${sdkSessionId ??
|
|
2190
|
+
return attachCopilotMirrorIdentity(message, `${sdkSessionId ?? mirrorScopeSessionId ?? "attempt"}:${message.role}:${index}`);
|
|
1787
2191
|
});
|
|
1788
2192
|
await dualWriteCopilotTranscriptBestEffort({
|
|
1789
2193
|
sessionFile: sessionFileForMirror,
|
|
2194
|
+
sessionId: openClawSessionIdForMirror,
|
|
1790
2195
|
sessionKey: readString(input.sessionKey),
|
|
1791
2196
|
agentId: readString(input.agentId),
|
|
1792
2197
|
messages: taggedMessages,
|
|
1793
|
-
idempotencyScope:
|
|
2198
|
+
idempotencyScope: mirrorScopeSessionId ? `copilot:${mirrorScopeSessionId}` : void 0,
|
|
1794
2199
|
config: input.config
|
|
1795
2200
|
}).catch((mirrorError) => {
|
|
1796
2201
|
console.warn("[copilot-attempt] dual-write transcript wrapper rejected unexpectedly", mirrorError);
|
|
@@ -1894,19 +2299,20 @@ function createPromptError(code, message, cause) {
|
|
|
1894
2299
|
if (cause !== void 0) error.cause = cause;
|
|
1895
2300
|
return error;
|
|
1896
2301
|
}
|
|
1897
|
-
function createSessionConfig(params, sdkModelId, sdkTools, resolvedAuth, systemMessageContent, effectiveWorkspaceDir, effectiveCwd, hooksBridgeOptions) {
|
|
2302
|
+
function createSessionConfig(params, sdkModelId, sdkTools, resolvedAuth, systemMessageContent, effectiveWorkspaceDir, effectiveCwd, onUserInputRequest, hooksBridgeOptions) {
|
|
1898
2303
|
const permissionPolicy = params.permissionPolicy ?? rejectAllPolicy;
|
|
1899
2304
|
const hooks = createHooksBridge(params.hooksConfig, hooksBridgeOptions);
|
|
1900
2305
|
const infiniteSessions = createInfiniteSessionConfig(params.infiniteSessionConfig);
|
|
1901
2306
|
return {
|
|
1902
2307
|
model: sdkModelId,
|
|
1903
2308
|
onPermissionRequest: createPermissionBridge(permissionPolicy),
|
|
2309
|
+
onUserInputRequest,
|
|
1904
2310
|
...hooks ? { hooks } : {},
|
|
1905
2311
|
...typeof params.enableSessionTelemetry === "boolean" ? { enableSessionTelemetry: params.enableSessionTelemetry } : {},
|
|
1906
2312
|
...infiniteSessions ? { infiniteSessions } : {},
|
|
1907
2313
|
reasoningEffort: params.reasoningEffort,
|
|
1908
2314
|
tools: sdkTools,
|
|
1909
|
-
availableTools: sdkTools
|
|
2315
|
+
availableTools: buildCopilotAvailableTools(sdkTools),
|
|
1910
2316
|
workingDirectory: effectiveCwd ?? effectiveWorkspaceDir ?? readResolvedAttemptPath(params.workspaceDir),
|
|
1911
2317
|
...effectiveWorkspaceDir && effectiveCwd && effectiveCwd !== effectiveWorkspaceDir ? { instructionDirectories: [effectiveWorkspaceDir] } : {},
|
|
1912
2318
|
...resolvedAuth.authMode === "gitHubToken" && resolvedAuth.gitHubToken ? { gitHubToken: resolvedAuth.gitHubToken } : {},
|
|
@@ -1916,6 +2322,9 @@ function createSessionConfig(params, sdkModelId, sdkTools, resolvedAuth, systemM
|
|
|
1916
2322
|
} } : {}
|
|
1917
2323
|
};
|
|
1918
2324
|
}
|
|
2325
|
+
function buildCopilotAvailableTools(sdkTools) {
|
|
2326
|
+
return [...new Set([...sdkTools.map((tool) => tool.name), ...COPILOT_ASK_USER_AVAILABLE_TOOLS])];
|
|
2327
|
+
}
|
|
1919
2328
|
async function createMessageOptions(params, context) {
|
|
1920
2329
|
const attachments = createPromptImageAttachments(await resolvePromptImages(params, context));
|
|
1921
2330
|
return attachments.length > 0 ? {
|
|
@@ -421,7 +421,7 @@ function createCopilotAgentHarness(options) {
|
|
|
421
421
|
async runAttempt(params) {
|
|
422
422
|
const attemptPromise = (async () => {
|
|
423
423
|
if (disposed) throw new Error("[copilot] harness has been disposed; cannot start new attempts");
|
|
424
|
-
const { resolvePoolAcquire, runCopilotAttempt } = await import("./attempt-
|
|
424
|
+
const { resolvePoolAcquire, runCopilotAttempt } = await import("./attempt-ArBh6GPT.js");
|
|
425
425
|
if (disposed) throw new Error("[copilot] harness was disposed while starting an attempt");
|
|
426
426
|
const poolAcquire = resolvePoolAcquire(params);
|
|
427
427
|
const pool = await getPool();
|
|
@@ -531,7 +531,7 @@ function createCopilotAgentHarness(options) {
|
|
|
531
531
|
};
|
|
532
532
|
const tracked = trackedSessions.get(openclawSessionId);
|
|
533
533
|
const currentCompactKey = computeSessionCompactKey(params);
|
|
534
|
-
const { resolvePoolAcquire } = await import("./attempt-
|
|
534
|
+
const { resolvePoolAcquire } = await import("./attempt-ArBh6GPT.js");
|
|
535
535
|
const resolvedPoolAcquire = resolvePoolAcquire(params);
|
|
536
536
|
const currentAuth = sessionAuthFields(resolvedPoolAcquire.auth);
|
|
537
537
|
const compatibleTracked = tracked?.compactKey === currentCompactKey && sessionAuthMatches(tracked, currentAuth) ? tracked : void 0;
|
|
@@ -617,7 +617,16 @@ function createCopilotAgentHarness(options) {
|
|
|
617
617
|
return {
|
|
618
618
|
ok: true,
|
|
619
619
|
compacted,
|
|
620
|
-
reason: compacted ? "copilot-sdk-history-compacted" : "already under target"
|
|
620
|
+
reason: compacted ? "copilot-sdk-history-compacted" : "already under target",
|
|
621
|
+
...compacted ? { result: {
|
|
622
|
+
summary: compactResult.summaryContent ?? "",
|
|
623
|
+
firstKeptEntryId: "",
|
|
624
|
+
tokensBefore: params.currentTokenCount ?? (compactResult.contextWindow?.currentTokens ?? 0) + compactResult.tokensRemoved,
|
|
625
|
+
tokensAfter: compactResult.contextWindow?.currentTokens,
|
|
626
|
+
details: compactResult,
|
|
627
|
+
sessionId: params.sessionId,
|
|
628
|
+
sessionFile: params.sessionFile
|
|
629
|
+
} } : {}
|
|
621
630
|
};
|
|
622
631
|
},
|
|
623
632
|
async dispose() {
|
package/dist/harness.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createCopilotAgentHarness } from "./harness-
|
|
1
|
+
import { t as createCopilotAgentHarness } from "./harness-D-3KWchY.js";
|
|
2
2
|
export { createCopilotAgentHarness };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createCopilotAgentHarness } from "./harness-
|
|
1
|
+
import { t as createCopilotAgentHarness } from "./harness-D-3KWchY.js";
|
|
2
2
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
3
3
|
//#region extensions/copilot/index.ts
|
|
4
4
|
function isRecord(value) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/copilot",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.11",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/copilot",
|
|
9
|
-
"version": "2026.6.
|
|
9
|
+
"version": "2026.6.11",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@github/copilot-sdk": "1.0.0-beta.9"
|
|
12
12
|
}
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/copilot",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.11",
|
|
4
4
|
"description": "OpenClaw GitHub Copilot agent runtime plugin (registers a `github-copilot` AgentHarness backed by @github/copilot-sdk over JSON-RPC to the GitHub Copilot CLI)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"minHostVersion": ">=2026.5.28"
|
|
26
26
|
},
|
|
27
27
|
"compat": {
|
|
28
|
-
"pluginApi": ">=2026.6.
|
|
28
|
+
"pluginApi": ">=2026.6.11"
|
|
29
29
|
},
|
|
30
30
|
"build": {
|
|
31
|
-
"openclawVersion": "2026.6.
|
|
31
|
+
"openclawVersion": "2026.6.11",
|
|
32
32
|
"bundledDist": false
|
|
33
33
|
},
|
|
34
34
|
"release": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"README.md"
|
|
48
48
|
],
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"openclaw": ">=2026.6.
|
|
50
|
+
"openclaw": ">=2026.6.11"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
53
|
"openclaw": {
|