mixdog 0.9.23 → 0.9.25
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/package.json +2 -1
- package/scripts/boot-smoke.mjs +1 -1
- package/scripts/channel-daemon-smoke.mjs +327 -9
- package/scripts/channel-daemon-stub.mjs +12 -1
- package/scripts/debounced-skills-async-save-test.mjs +57 -0
- package/scripts/explore-bench-tmp.mjs +17 -0
- package/scripts/find-fuzzy-hidden-test.mjs +145 -0
- package/scripts/mcp-grace-deferred-test.mjs +149 -0
- package/scripts/tool-smoke.mjs +38 -30
- package/src/defaults/cycle3-review-prompt.md +11 -4
- package/src/defaults/memory-promote-prompt.md +9 -0
- package/src/rules/agent/30-explorer.md +6 -0
- package/src/rules/shared/01-tool.md +11 -4
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +76 -1
- package/src/runtime/agent/orchestrator/config.mjs +33 -7
- package/src/runtime/agent/orchestrator/context/collect.mjs +43 -8
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +39 -0
- package/src/runtime/agent/orchestrator/mcp/client.mjs +145 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +38 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +39 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +24 -7
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +7 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +40 -6
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +13 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +62 -24
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -6
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +20 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +34 -3
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +220 -27
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +61 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +43 -16
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +54 -5
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +97 -54
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +49 -31
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +35 -2
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +70 -21
- package/src/runtime/channels/backends/discord.mjs +10 -3
- package/src/runtime/channels/lib/crash-log.mjs +4 -2
- package/src/runtime/channels/lib/inbound-handler.mjs +45 -1
- package/src/runtime/channels/lib/output-forwarder.mjs +2 -1
- package/src/runtime/channels/lib/owned-runtime.mjs +65 -180
- package/src/runtime/channels/lib/owner-heartbeat.mjs +9 -13
- package/src/runtime/channels/lib/runtime-paths.mjs +6 -6
- package/src/runtime/channels/lib/tool-dispatch.mjs +9 -17
- package/src/runtime/channels/lib/tool-format.mjs +7 -2
- package/src/runtime/channels/lib/worker-main.mjs +9 -28
- package/src/runtime/memory/lib/cycle-scheduler.mjs +17 -1
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +59 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +10 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +79 -9
- package/src/runtime/memory/lib/query-handlers.mjs +4 -1
- package/src/runtime/memory/lib/recall-format.mjs +7 -3
- package/src/runtime/memory/tool-defs.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +130 -2
- package/src/runtime/shared/background-tasks.mjs +1 -1
- package/src/runtime/shared/config.mjs +53 -1
- package/src/runtime/shared/tool-execution-contract.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +19 -0
- package/src/runtime/shared/update-checker.mjs +3 -0
- package/src/runtime/shared/user-data-guard.mjs +66 -0
- package/src/session-runtime/config-lifecycle.mjs +175 -15
- package/src/session-runtime/mcp-glue.mjs +30 -0
- package/src/session-runtime/runtime-core.mjs +91 -7
- package/src/session-runtime/session-turn-api.mjs +42 -16
- package/src/session-runtime/tool-catalog.mjs +44 -0
- package/src/standalone/channel-admin.mjs +32 -3
- package/src/standalone/channel-daemon-client.mjs +3 -1
- package/src/standalone/channel-daemon-transport.mjs +202 -8
- package/src/standalone/channel-daemon.mjs +54 -17
- package/src/standalone/channel-worker.mjs +18 -7
- package/src/standalone/explore-tool.mjs +87 -15
- package/src/tui/App.jsx +2 -2
- package/src/tui/components/StatusLine.jsx +3 -3
- package/src/tui/components/ToolExecution.jsx +14 -2
- package/src/tui/components/TranscriptItem.jsx +1 -1
- package/src/tui/dist/index.mjs +246 -47
- package/src/tui/engine/agent-job-feed.mjs +47 -3
- package/src/tui/engine/notification-plan.mjs +5 -0
- package/src/tui/engine/session-api.mjs +6 -1
- package/src/tui/engine/tool-card-results.mjs +14 -5
- package/src/tui/engine/turn.mjs +9 -2
- package/src/tui/engine.mjs +31 -12
- package/src/ui/statusline-agents.mjs +36 -0
- package/src/ui/statusline.mjs +15 -5
- package/src/workflows/default/WORKFLOW.md +29 -38
- package/src/workflows/solo/WORKFLOW.md +15 -20
- package/src/runtime/channels/lib/seat-lock.mjs +0 -196
|
@@ -37,7 +37,7 @@ import { startChildGuardian } from '../../../shared/child-guardian.mjs';
|
|
|
37
37
|
// transition). shell-jobs.mjs imports stripAnsi from this module, so this is
|
|
38
38
|
// a static cycle — safe because neither binding is touched at module-eval
|
|
39
39
|
// time, only when the respective functions actually run.
|
|
40
|
-
import { adoptForegroundShellJob } from './builtin/shell-jobs.mjs';
|
|
40
|
+
import { adoptForegroundShellJob, killShellJob } from './builtin/shell-jobs.mjs';
|
|
41
41
|
import {
|
|
42
42
|
_maybeEncodePowerShellCommand,
|
|
43
43
|
extractPowerShellCommandInner,
|
|
@@ -494,6 +494,7 @@ export function execShellCommand({
|
|
|
494
494
|
autoBackgroundMs,
|
|
495
495
|
onProgress,
|
|
496
496
|
clientHostPid,
|
|
497
|
+
backgroundOnTimeout,
|
|
497
498
|
}) {
|
|
498
499
|
return new Promise(async (resolve) => {
|
|
499
500
|
const taskId = `shell_${randomUUID().slice(0, 8)}`;
|
|
@@ -723,16 +724,20 @@ export function execShellCommand({
|
|
|
723
724
|
if (grace.unref) grace.unref();
|
|
724
725
|
});
|
|
725
726
|
|
|
726
|
-
// Auto-background transition (CC
|
|
727
|
-
//
|
|
728
|
-
//
|
|
729
|
-
//
|
|
730
|
-
//
|
|
731
|
-
//
|
|
732
|
-
//
|
|
733
|
-
//
|
|
734
|
-
//
|
|
735
|
-
|
|
727
|
+
// Auto-background transition (CC startBackgrounding analogue). Two triggers
|
|
728
|
+
// resolve the call immediately with a 'backgrounded' result while the
|
|
729
|
+
// child keeps running, adopted into the shell-jobs registry but still
|
|
730
|
+
// owned by this CLI process:
|
|
731
|
+
// 1. the optional autoBackgroundMs soft threshold (MIXDOG_SHELL_AUTO_
|
|
732
|
+
// BACKGROUND_MS opt-in) — an EARLIER promotion before the timeout, and
|
|
733
|
+
// 2. the foreground timeout deadline (backgroundOnTimeout) — the default
|
|
734
|
+
// promote-on-timeout that replaces the old tree-kill.
|
|
735
|
+
// Either way the adopted job runs UNLIMITED (timeoutMs 0, matching the
|
|
736
|
+
// async default): the original foreground timeout no longer bounds it, and
|
|
737
|
+
// the adopted-job cap poll still enforces the 100 MB output ceiling.
|
|
738
|
+
// Mutually exclusive with settle() via the autoBackgrounded flag set
|
|
739
|
+
// synchronously at the top before any await.
|
|
740
|
+
const _autoBackground = async ({ reason = 'threshold' } = {}) => {
|
|
736
741
|
// Win the race: bail if a terminal transition already happened, and
|
|
737
742
|
// claim the transition synchronously so a concurrently-queued settle()
|
|
738
743
|
// (which checks autoBackgrounded) becomes inert.
|
|
@@ -740,16 +745,18 @@ export function execShellCommand({
|
|
|
740
745
|
if (child.exitCode != null || child.signalCode != null) return;
|
|
741
746
|
autoBackgrounded = true;
|
|
742
747
|
// The foreground capture is over; stop the local watchdogs/timers so
|
|
743
|
-
// they cannot treeKill the now-adopted child. The
|
|
744
|
-
//
|
|
748
|
+
// they cannot treeKill the now-adopted child. The adopted job runs
|
|
749
|
+
// unlimited; refreshShellJob only enforces the output cap.
|
|
745
750
|
if (timer) { clearTimeout(timer); timer = null; }
|
|
746
751
|
_clearProgressTimer();
|
|
747
752
|
if (sizeWatchdog) { clearInterval(sizeWatchdog); sizeWatchdog = null; }
|
|
748
753
|
if (autoBgTimer) { clearTimeout(autoBgTimer); autoBgTimer = null; }
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
754
|
+
// Keep the abort handler ATTACHED through the promotion window. A user
|
|
755
|
+
// cancel racing in after promotion starts must still bring the adopted
|
|
756
|
+
// child down — the handler's treeKill(child) does exactly that (settle()
|
|
757
|
+
// is inert once autoBackgrounded, but the kill itself still lands, and
|
|
758
|
+
// refreshShellJob then flags the job failed). We only detach on a real
|
|
759
|
+
// settle() or on the adoption-failure fallback below.
|
|
753
760
|
// Every subsequent stdout/stderr chunk must hit disk — the call is
|
|
754
761
|
// about to resolve and nobody will drain the in-memory buffers again.
|
|
755
762
|
try { taskOutput.forceSpill(); } catch {}
|
|
@@ -766,7 +773,9 @@ export function execShellCommand({
|
|
|
766
773
|
command,
|
|
767
774
|
cwd,
|
|
768
775
|
pid: child.pid,
|
|
769
|
-
|
|
776
|
+
// Unlimited: the promoted job is no longer bounded by the foreground
|
|
777
|
+
// timeout (matches the async omitted-default behavior).
|
|
778
|
+
timeoutMs: 0,
|
|
770
779
|
mergeStderr: false,
|
|
771
780
|
stdoutPath,
|
|
772
781
|
stderrPath,
|
|
@@ -777,6 +786,18 @@ export function execShellCommand({
|
|
|
777
786
|
} catch {
|
|
778
787
|
job = null;
|
|
779
788
|
}
|
|
789
|
+
// Adoption failed AFTER the foreground timers/size-watchdog were already
|
|
790
|
+
// torn down. Do NOT resolve as backgrounded — that would leave the child
|
|
791
|
+
// running unlimited with no task_id and no watcher. Release the claim and
|
|
792
|
+
// fall back to the old kill path so the command never outlives a failed
|
|
793
|
+
// promotion. (The abort handler is still attached, so an in-flight cancel
|
|
794
|
+
// is honored by the kill path too.)
|
|
795
|
+
if (!job) {
|
|
796
|
+
autoBackgrounded = false;
|
|
797
|
+
if (reason === 'timeout') timedOut = true; else killed = true;
|
|
798
|
+
_treeKillForceSettle();
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
780
801
|
// Wire the lifecycle: on close, write the exit-code file FIRST then
|
|
781
802
|
// touch donePath STRICTLY AFTER — the exact ordering refreshShellJob()
|
|
782
803
|
// gates completion on (donePath visible ⇒ exit file fully flushed).
|
|
@@ -787,6 +808,14 @@ export function execShellCommand({
|
|
|
787
808
|
try { writeFileSync(job.donePath, ''); } catch {}
|
|
788
809
|
});
|
|
789
810
|
}
|
|
811
|
+
// Adoption committed. If a cancel already fired (before or during the
|
|
812
|
+
// adoption window), bring the now-adopted child down via its jobId so the
|
|
813
|
+
// promotion can't outlive a user abort. Idempotent with the still-attached
|
|
814
|
+
// abort handler's treeKill.
|
|
815
|
+
if (abortSignal && abortSignal.aborted) {
|
|
816
|
+
try { killShellJob(job.jobId); } catch {}
|
|
817
|
+
try { treeKill(child); } catch {}
|
|
818
|
+
}
|
|
790
819
|
// Snapshot the partial output captured so far for the immediate result.
|
|
791
820
|
let stdout = '';
|
|
792
821
|
let stderr = '';
|
|
@@ -795,7 +824,10 @@ export function execShellCommand({
|
|
|
795
824
|
try { stderr = await taskOutput.getStderr(); }
|
|
796
825
|
catch (err) { taskOutput.writeError = taskOutput.writeError || err; }
|
|
797
826
|
const jobId = job ? job.jobId : null;
|
|
798
|
-
const secs = Math.round(
|
|
827
|
+
const secs = Math.max(0, Math.round((Date.now() - _startMs) / 1000));
|
|
828
|
+
const _verb = reason === 'timeout'
|
|
829
|
+
? `moved to background at timeout after ${secs}s`
|
|
830
|
+
: `auto-backgrounded after ${secs}s`;
|
|
799
831
|
resolve(
|
|
800
832
|
new ExecResult({
|
|
801
833
|
stdout,
|
|
@@ -814,14 +846,31 @@ export function execShellCommand({
|
|
|
814
846
|
backgrounded: true,
|
|
815
847
|
jobId,
|
|
816
848
|
backgroundMessage: jobId
|
|
817
|
-
?
|
|
818
|
-
:
|
|
849
|
+
? `${_verb}; still running — completion will be delivered as a background task notification. Use task with task_id:${jobId} only for manual wait/status/read/cancel.`
|
|
850
|
+
: `${_verb}; still running`,
|
|
819
851
|
}),
|
|
820
852
|
);
|
|
821
853
|
};
|
|
822
854
|
|
|
823
855
|
if (timeoutMs > 0) {
|
|
824
856
|
timer = setTimeout(() => {
|
|
857
|
+
// Promote-on-timeout: if the caller allows backgrounding and the child
|
|
858
|
+
// is still running (not a trailing-`&` detach), adopt it as a tracked
|
|
859
|
+
// background job instead of tree-killing it. Falls through to the old
|
|
860
|
+
// kill path for disallowed/opted-out commands (backgroundOnTimeout
|
|
861
|
+
// false) or when a terminal transition already won the race.
|
|
862
|
+
if (
|
|
863
|
+
backgroundOnTimeout &&
|
|
864
|
+
!_isBackground &&
|
|
865
|
+
!settled &&
|
|
866
|
+
!autoBackgrounded &&
|
|
867
|
+
!killed &&
|
|
868
|
+
child.exitCode == null &&
|
|
869
|
+
child.signalCode == null
|
|
870
|
+
) {
|
|
871
|
+
_autoBackground({ reason: 'timeout' });
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
825
874
|
timedOut = true;
|
|
826
875
|
_treeKillForceSettle();
|
|
827
876
|
}, timeoutMs);
|
|
@@ -435,14 +435,21 @@ class DiscordBackend {
|
|
|
435
435
|
const msg = await ch.messages.fetch(messageId);
|
|
436
436
|
if (msg.attachments.size === 0) return [];
|
|
437
437
|
const results = [];
|
|
438
|
+
// Optional filter bounds what gets fetched (e.g. image/* only) so a
|
|
439
|
+
// caller after images never pulls unrelated large attachments.
|
|
440
|
+
const filter = typeof opts.filter === "function" ? opts.filter : null;
|
|
438
441
|
for (const att of msg.attachments.values()) {
|
|
439
|
-
const
|
|
440
|
-
results.push({
|
|
442
|
+
const meta = {
|
|
441
443
|
id: att.id,
|
|
442
|
-
path,
|
|
443
444
|
name: safeAttName(att),
|
|
444
445
|
contentType: att.contentType ?? "unknown",
|
|
445
446
|
size: att.size
|
|
447
|
+
};
|
|
448
|
+
if (filter && !filter(meta)) continue;
|
|
449
|
+
const path = await this.downloadSingleAttachment(att, opts);
|
|
450
|
+
results.push({
|
|
451
|
+
...meta,
|
|
452
|
+
path
|
|
446
453
|
});
|
|
447
454
|
}
|
|
448
455
|
return results;
|
|
@@ -23,8 +23,9 @@ function isChannelsDegraded() { return _channelsDegraded; }
|
|
|
23
23
|
try {
|
|
24
24
|
process.stderr.on('error', (e) => {
|
|
25
25
|
if (e && (e.code === 'EPIPE' || /EPIPE/.test(String(e.message || '')))) {
|
|
26
|
+
// Parent stdio pipe loss stops stderr writes only. It is NOT runtime
|
|
27
|
+
// corruption, so it must not degrade tool dispatch (_channelsDegraded).
|
|
26
28
|
_stderrBroken = true;
|
|
27
|
-
_channelsDegraded = true;
|
|
28
29
|
}
|
|
29
30
|
});
|
|
30
31
|
} catch {}
|
|
@@ -75,7 +76,8 @@ ${err instanceof Error ? err.stack : ""}
|
|
|
75
76
|
_writeCrashLine(crashLog, msg);
|
|
76
77
|
}
|
|
77
78
|
if (err instanceof Error && err.message.includes("EPIPE")) {
|
|
78
|
-
|
|
79
|
+
// EPIPE = a broken pipe (parent stdio/IPC gone), not corrupted runtime
|
|
80
|
+
// state. Stop writing to the dead pipe but keep serving tool calls.
|
|
79
81
|
_stderrBroken = true;
|
|
80
82
|
}
|
|
81
83
|
crashLogging = false;
|
|
@@ -10,6 +10,9 @@ import { isNetworkError, retryOnNetwork } from "./network-retry.mjs";
|
|
|
10
10
|
// preserving): serial inbound queue, backend.onMessage transcript (re)bind +
|
|
11
11
|
// steal logic, and handleInbound voice-transcription + parent notify. Bound to
|
|
12
12
|
// live runtime getters and shared primitives.
|
|
13
|
+
function isImageAttachment(contentType) {
|
|
14
|
+
return typeof contentType === "string" && contentType.toLowerCase().startsWith("image/");
|
|
15
|
+
}
|
|
13
16
|
export function createInboundHandler({
|
|
14
17
|
getBackend,
|
|
15
18
|
getConfig,
|
|
@@ -283,6 +286,46 @@ async function handleInbound(msg, route, options = {}) {
|
|
|
283
286
|
}
|
|
284
287
|
}
|
|
285
288
|
const hasVoiceAtt = voiceAtts.length > 0;
|
|
289
|
+
// ── Inbound image attachments → downloaded local paths (vision) ──────
|
|
290
|
+
// Mirror the voice path: download image/* attachments to the inbox and
|
|
291
|
+
// hand their local paths downstream so the agent session can attach them
|
|
292
|
+
// as real image content blocks. A short per-attempt timeout bounds the
|
|
293
|
+
// serial inboundQueue against a slow/broken image; on failure we degrade
|
|
294
|
+
// to the metadata-only marker (attMeta below) instead of dropping.
|
|
295
|
+
const imageAtts = msg.attachments.filter((a) => isImageAttachment(a.contentType));
|
|
296
|
+
let imagePaths = [];
|
|
297
|
+
if (imageAtts.length > 0) {
|
|
298
|
+
try {
|
|
299
|
+
const files = (await retryOnNetwork(
|
|
300
|
+
() => getBackend().downloadAttachment(msg.chatId, msg.messageId, {
|
|
301
|
+
timeoutMs: 20_000,
|
|
302
|
+
filter: (a) => isImageAttachment(a.contentType),
|
|
303
|
+
}),
|
|
304
|
+
{ label: "image.download" }
|
|
305
|
+
)) || [];
|
|
306
|
+
imagePaths = imageAtts
|
|
307
|
+
.map((a) => files.find((df) => df.id === a.id) ?? null)
|
|
308
|
+
.filter(Boolean)
|
|
309
|
+
.map((f) => f.path)
|
|
310
|
+
.filter((p) => typeof p === "string" && p.length > 0);
|
|
311
|
+
if (imagePaths.length > 0) {
|
|
312
|
+
process.stderr.write(`mixdog: inbound images downloaded (${imagePaths.length})\n`);
|
|
313
|
+
}
|
|
314
|
+
} catch (err) {
|
|
315
|
+
const netFail = isNetworkError(err);
|
|
316
|
+
process.stderr.write(`mixdog: image.download error${netFail ? " (network, retries exhausted)" : ""}: ${err}\n`);
|
|
317
|
+
const marker = netFail
|
|
318
|
+
? "[attachment: image download failed (network)]"
|
|
319
|
+
: "[attachment: image download failed]";
|
|
320
|
+
text = text ? `${text} ${marker}` : marker;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// An image-only message can arrive with empty text; channelNotificationModelContent
|
|
324
|
+
// drops empty content (runtime-core), which would strip meta.image_paths and lose
|
|
325
|
+
// the image. Give it a non-empty marker so the notification (and its images) flow.
|
|
326
|
+
if (imagePaths.length > 0 && !String(text || "").trim()) {
|
|
327
|
+
text = "[image]";
|
|
328
|
+
}
|
|
286
329
|
const attMeta = msg.attachments.length > 0 && !hasVoiceAtt ? {
|
|
287
330
|
attachment_count: String(msg.attachments.length),
|
|
288
331
|
attachments: msg.attachments.map((a) => `${a.name} (${a.contentType}, ${(a.size / 1024).toFixed(0)}KB)`).join("; ")
|
|
@@ -300,7 +343,8 @@ async function handleInbound(msg, route, options = {}) {
|
|
|
300
343
|
...route.sourceLabel ? { source_label: route.sourceLabel } : {}
|
|
301
344
|
} : {},
|
|
302
345
|
...attMeta,
|
|
303
|
-
...msg.imagePath ? { image_path: msg.imagePath } : {}
|
|
346
|
+
...msg.imagePath ? { image_path: msg.imagePath } : {},
|
|
347
|
+
...imagePaths.length > 0 ? { image_paths: JSON.stringify(imagePaths) } : {}
|
|
304
348
|
};
|
|
305
349
|
const notificationContent = messageBody;
|
|
306
350
|
sendNotifyToParent("notifications/claude/channel", {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
formatToolSurface,
|
|
7
7
|
isExplorerSurface,
|
|
8
8
|
isMemorySurface,
|
|
9
|
+
stripToolPrefix,
|
|
9
10
|
} from "../../shared/tool-surface.mjs";
|
|
10
11
|
import {
|
|
11
12
|
cwdToProjectSlug,
|
|
@@ -726,7 +727,7 @@ ${_bt.trim()}` : _bt.trim();
|
|
|
726
727
|
// The non-set checks are inlined rather than delegated to the imported
|
|
727
728
|
// isHidden, because that helper would re-consult the module-local
|
|
728
729
|
// HIDDEN_TOOLS Set and ignore the OutputForwarder static.
|
|
729
|
-
if (OutputForwarder.HIDDEN_TOOLS.has(name)) return true;
|
|
730
|
+
if (OutputForwarder.HIDDEN_TOOLS.has(name) || OutputForwarder.HIDDEN_TOOLS.has(stripToolPrefix(name))) return true;
|
|
730
731
|
if (name === "reply" || name === "fetch") return true;
|
|
731
732
|
return false;
|
|
732
733
|
};
|