@yanlinglabs/winter-agent-runtime 0.0.27 → 0.0.29
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 +7 -1
- package/dist/context/attachments.d.ts +37 -0
- package/dist/context/seam.d.ts +19 -1
- package/dist/embedded-host.d.ts +14 -0
- package/dist/embedded-host.js +11 -1
- package/dist/embedded-protocol.d.ts +17 -1
- package/dist/embedded-worker.js +20 -3
- package/dist/embedded.js +4 -3
- package/dist/engine.d.ts +23 -0
- package/dist/hooks/additional-context.d.ts +20 -0
- package/dist/hooks/async-hooks.d.ts +64 -0
- package/dist/hooks/command-invoker.d.ts +8 -1
- package/dist/hooks/registry.d.ts +6 -0
- package/dist/hooks/runner.d.ts +22 -0
- package/dist/index-8jgwp1px.js +533 -0
- package/dist/{index-rkhh0457.js → index-eyddzcgs.js} +2 -2
- package/dist/{index-584yahed.js → index-gmxxtqpe.js} +176 -107
- package/dist/{index-9qgkpv56.js → index-jz5d90c6.js} +604 -587
- package/dist/index.js +2 -1
- package/dist/mcp/client.d.ts +16 -1
- package/dist/mcp/test-fixtures.d.ts +2 -0
- package/dist/mcp/transports/stdio.d.ts +19 -0
- package/dist/mcp-client.d.ts +28 -0
- package/dist/mcp-client.js +23 -0
- package/dist/permissions/paths.d.ts +5 -0
- package/dist/process-groups.d.ts +22 -0
- package/dist/provider/classifier/model-classifier.d.ts +12 -0
- package/dist/store/dialect.d.ts +1 -1
- package/dist/store/provider-state.d.ts +14 -1
- package/dist/subagents/child-handle.d.ts +8 -0
- package/dist/testing.js +3 -2
- package/dist/tools/registry.d.ts +6 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -4
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getRegisteredTool,
|
|
13
13
|
listRegisteredTools,
|
|
14
14
|
rebrandStandingServerTools,
|
|
15
|
+
mcpServerHasRegistrations,
|
|
15
16
|
STRUCTURED_OUTPUT_TOOL_NAME,
|
|
16
17
|
looksLikeCommand,
|
|
17
18
|
registerChildEngineFactory,
|
|
@@ -86,7 +87,7 @@ import {
|
|
|
86
87
|
providerCredentialRef2,
|
|
87
88
|
createModelClassifier2,
|
|
88
89
|
selectClassifierRoute2
|
|
89
|
-
} from "./index-
|
|
90
|
+
} from "./index-jz5d90c6.js";
|
|
90
91
|
import {
|
|
91
92
|
createInMemoryChannel2
|
|
92
93
|
} from "./index-97t2rmtf.js";
|
|
@@ -473,6 +474,64 @@ async function cleanupWorkspace(workspace) {
|
|
|
473
474
|
}
|
|
474
475
|
|
|
475
476
|
// src/subagents/child-engine.ts
|
|
477
|
+
var liveChildScopedServerNames = new Set;
|
|
478
|
+
var GENERATION_TEARDOWN_WAIT_MS = 5000;
|
|
479
|
+
function renameMcpReference(entry, renames) {
|
|
480
|
+
for (const [declared, actual] of renames) {
|
|
481
|
+
const prefix = `mcp__${declared}`;
|
|
482
|
+
if (entry === prefix || entry.startsWith(`${prefix}__`) || entry.startsWith(`${prefix}(`))
|
|
483
|
+
return `mcp__${actual}${entry.slice(prefix.length)}`;
|
|
484
|
+
}
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
function allocateChildScopedServers(declared, parentVisible, prefer, parentDeclared) {
|
|
488
|
+
const claimed = [];
|
|
489
|
+
const inUse = (name) => liveChildScopedServerNames.has(name) || parentVisible.has(name) || mcpServerHasRegistrations(name);
|
|
490
|
+
const servers = {};
|
|
491
|
+
const actual = new Map;
|
|
492
|
+
const notes = [];
|
|
493
|
+
const claim = (name) => {
|
|
494
|
+
liveChildScopedServerNames.add(name);
|
|
495
|
+
claimed.push(name);
|
|
496
|
+
};
|
|
497
|
+
for (const [name, cfg] of Object.entries(declared)) {
|
|
498
|
+
if (cfg.type === "sdk") {
|
|
499
|
+
if (inUse(name)) {
|
|
500
|
+
notes.push(parentVisible.has(name) && parentDeclared?.[name]?.type === "sdk" ? `mcpServers declares the in-process server "${name}", which this session already has -- the session's "${name}" is used` : parentVisible.has(name) ? `mcpServers declares the in-process server "${name}", but this session's "${name}" is a different server -- this agent's own in-process "${name}" is not connected, and the session's is what this agent sees` : `mcpServers declares the in-process server "${name}", which another agent in this session is using -- this agent's own in-process "${name}" is not connected`);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
claim(name);
|
|
504
|
+
servers[name] = cfg;
|
|
505
|
+
actual.set(name, name);
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
const free = (candidate) => !inUse(candidate) && (candidate === name || !(candidate in declared));
|
|
509
|
+
let pick = prefer?.get(name);
|
|
510
|
+
if (pick === undefined || !free(pick))
|
|
511
|
+
pick = free(name) ? name : undefined;
|
|
512
|
+
for (let n = 2;pick === undefined; n++)
|
|
513
|
+
if (free(`${name}_${n}`))
|
|
514
|
+
pick = `${name}_${n}`;
|
|
515
|
+
claim(pick);
|
|
516
|
+
servers[pick] = cfg;
|
|
517
|
+
actual.set(name, pick);
|
|
518
|
+
if (pick !== name)
|
|
519
|
+
notes.push(`mcpServers declares "${name}", which is already in use in this session -- this agent's own "${name}" is connected as "${pick}" (its tools are named mcp__${pick}__<tool>)`);
|
|
520
|
+
}
|
|
521
|
+
let released = false;
|
|
522
|
+
return {
|
|
523
|
+
servers,
|
|
524
|
+
actual,
|
|
525
|
+
notes,
|
|
526
|
+
release: () => {
|
|
527
|
+
if (released)
|
|
528
|
+
return;
|
|
529
|
+
released = true;
|
|
530
|
+
for (const name of claimed)
|
|
531
|
+
liveChildScopedServerNames.delete(name);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
}
|
|
476
535
|
function createChildEngineFactory(deps) {
|
|
477
536
|
return (runCtx) => ({
|
|
478
537
|
spawn(req, inherit) {
|
|
@@ -487,8 +546,20 @@ async function spawnChildEngine(req, inherit, runCtx, deps) {
|
|
|
487
546
|
const env = deps.env ?? process.env;
|
|
488
547
|
const { depth: spawnDepth } = checkAndRegisterSpawn({ parentKey: runCtx.parentAgentId ?? runCtx.parentSessionId, childKey: agentId, env, ...deps.parentBrand !== undefined ? { brand: deps.parentBrand } : {} });
|
|
489
548
|
let spawnRegistered = true;
|
|
549
|
+
let pendingServerRelease;
|
|
490
550
|
try {
|
|
491
|
-
let startGeneration = function(config, initialMessages, liveText, agentSystemPrompt) {
|
|
551
|
+
let startGeneration = function(config, initialMessages, liveText, agentSystemPrompt, servers) {
|
|
552
|
+
const ownServers = Object.keys(servers.servers).length > 0;
|
|
553
|
+
if (ownServers)
|
|
554
|
+
config = { ...config, mcpServers: servers.servers };
|
|
555
|
+
const renames = [...servers.actual].filter(([declared, actual]) => declared !== actual);
|
|
556
|
+
if (renames.length > 0 && config.disallowedTools !== undefined) {
|
|
557
|
+
const carried = config.disallowedTools.flatMap((entry) => {
|
|
558
|
+
const renamed = renameMcpReference(entry, renames);
|
|
559
|
+
return renamed !== undefined ? [entry, renamed] : [entry];
|
|
560
|
+
});
|
|
561
|
+
config = { ...config, disallowedTools: [...new Set(carried)] };
|
|
562
|
+
}
|
|
492
563
|
const channel = createInMemoryChannel2();
|
|
493
564
|
currentSink = channel.host.output;
|
|
494
565
|
const startedAt = Date.now();
|
|
@@ -675,48 +746,63 @@ async function spawnChildEngine(req, inherit, runCtx, deps) {
|
|
|
675
746
|
}
|
|
676
747
|
};
|
|
677
748
|
})();
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
749
|
+
let handedOver = false;
|
|
750
|
+
try {
|
|
751
|
+
lastGenerationDone = runEngine2({
|
|
752
|
+
config,
|
|
753
|
+
contextAccountant: childAccountant,
|
|
754
|
+
...childProvider.identity !== undefined ? { providerIdentity: childProvider.identity } : {},
|
|
755
|
+
input: channel.runtime.input,
|
|
756
|
+
output: snapshottingOutput,
|
|
757
|
+
provider: childProvider.provider,
|
|
758
|
+
...agentSystemPrompt !== undefined && agentSystemPrompt.length > 0 ? { agentSystemPrompt } : {},
|
|
759
|
+
...req.fork === true && inherit.requestLayout !== undefined ? { exactRequestLayout: inherit.requestLayout } : {},
|
|
760
|
+
subagentHooks: {
|
|
761
|
+
agentType: req.agentType ?? req.builtinAgentType ?? (req.fork === true ? "fork" : "general-purpose"),
|
|
762
|
+
agentTranscriptPath: childStore !== undefined && childDurableRoot !== undefined ? transcriptPath : ""
|
|
763
|
+
},
|
|
764
|
+
...req.definition?.omitProjectContext === true ? { omitProjectContext: true } : {},
|
|
765
|
+
...writer !== undefined ? { store: writer } : {},
|
|
766
|
+
...initialMessages.length > 0 ? { initialMessages } : {},
|
|
767
|
+
...!ownServers && parentMcp?.stateSource !== undefined ? { mcpServerStateSource: parentMcp.stateSource } : {},
|
|
768
|
+
...!ownServers && parentMcp?.controlSeam !== undefined ? { mcpControlSeam: parentMcp.controlSeam } : {},
|
|
769
|
+
...(() => {
|
|
770
|
+
const merged = { ...parentMcp?.serverRenames ?? {}, ...Object.fromEntries(renames.map(([declared, actual]) => [actual, declared])) };
|
|
771
|
+
return Object.keys(merged).length > 0 ? { mcpServerRenames: merged } : {};
|
|
772
|
+
})(),
|
|
773
|
+
...parentMcp?.visibleServerNames !== undefined ? { inheritedMcpServerNames: ownServerNames.size === 0 ? parentMcp.visibleServerNames : () => parentMcp.visibleServerNames().filter((name) => !ownServerNames.has(name)) } : {},
|
|
774
|
+
...deps.systemPromptAssembler !== undefined ? { systemPromptAssembler: deps.systemPromptAssembler } : {},
|
|
775
|
+
...deps.skillListing !== undefined ? { skillListing: deps.skillListing } : {},
|
|
776
|
+
...deps.describeModel !== undefined ? { describeModel: deps.describeModel } : {},
|
|
777
|
+
...deps.priceUsage !== undefined ? {
|
|
778
|
+
priceUsage: (modelKey, usage) => deps.priceUsage(modelKey === resolvedModel.effectiveModel && childProvider.identity !== undefined ? childProvider.identity.modelKey : modelKey, usage)
|
|
779
|
+
} : {},
|
|
780
|
+
...deps.usageRowFacts !== undefined ? {
|
|
781
|
+
usageRowFacts: (modelKey) => deps.usageRowFacts(modelKey === resolvedModel.effectiveModel && childProvider.identity !== undefined ? childProvider.identity.modelKey : modelKey)
|
|
782
|
+
} : {},
|
|
783
|
+
...runCtx.recordDescendantCost !== undefined ? { onPricedGeneration: runCtx.recordDescendantCost } : {},
|
|
784
|
+
...runCtx.budgetExceeded !== undefined ? { ancestorBudgetExceeded: () => runCtx.budgetExceeded() } : {},
|
|
785
|
+
...deps.resolveAuxiliaryModel !== undefined ? { resolveAuxiliaryModel: deps.resolveAuxiliaryModel } : {},
|
|
786
|
+
...deps.resolveToolSecret !== undefined ? { resolveToolSecret: deps.resolveToolSecret } : {},
|
|
787
|
+
...deps.settingsRules !== undefined ? { settingsRules: deps.settingsRules } : {},
|
|
788
|
+
...childDurableRoot !== undefined ? { winterHome: childDurableRoot } : {},
|
|
789
|
+
...deps.structuredOutput !== undefined ? { structuredOutput: deps.structuredOutput } : {},
|
|
790
|
+
...deps.extraHookEntries !== undefined ? { extraHookEntries: deps.extraHookEntries } : {},
|
|
791
|
+
...ownCompactionController !== undefined ? { compactionController: ownCompactionController } : {},
|
|
792
|
+
env
|
|
793
|
+
}).catch((err) => {
|
|
794
|
+
const reason = err instanceof Error && err.message.length > 0 ? err.message : String(err ?? "");
|
|
795
|
+
settle("failed", reason.length > 0 ? `child engine exited: ${reason}` : "child engine process exited unexpectedly");
|
|
796
|
+
}).finally(servers.release).then(() => {
|
|
797
|
+
return;
|
|
798
|
+
}, () => {
|
|
799
|
+
return;
|
|
800
|
+
});
|
|
801
|
+
handedOver = true;
|
|
802
|
+
} finally {
|
|
803
|
+
if (!handedOver)
|
|
804
|
+
servers.release();
|
|
805
|
+
}
|
|
720
806
|
channel.host.output.write({ type: "user", text: liveText });
|
|
721
807
|
}, resolveParentRules = function() {
|
|
722
808
|
const live = runCtx.getParentRules?.();
|
|
@@ -807,7 +893,8 @@ async function spawnChildEngine(req, inherit, runCtx, deps) {
|
|
|
807
893
|
for (const [name, cfg] of Object.entries(spec))
|
|
808
894
|
childScopedMcpServers[name] = cfg;
|
|
809
895
|
}
|
|
810
|
-
const
|
|
896
|
+
const ownServerNames = new Set(Object.entries(childScopedMcpServers).filter(([, cfg]) => cfg.type !== "sdk").map(([name]) => name));
|
|
897
|
+
const parentVisibleServers = () => new Set(parentMcp?.visibleServerNames?.() ?? []);
|
|
811
898
|
const workspaceResult = await createWorkspace({
|
|
812
899
|
parentCwd: inherit.sessionRoot,
|
|
813
900
|
...req.isolation !== undefined ? { isolation: req.isolation } : {},
|
|
@@ -852,6 +939,8 @@ async function spawnChildEngine(req, inherit, runCtx, deps) {
|
|
|
852
939
|
let currentSink;
|
|
853
940
|
let currentSettle;
|
|
854
941
|
let currentUsage;
|
|
942
|
+
let lastGenerationDone = Promise.resolve();
|
|
943
|
+
let pendingResume;
|
|
855
944
|
const baseConfig = {
|
|
856
945
|
sessionId: runCtx.parentSessionId,
|
|
857
946
|
cwd: workspace.root,
|
|
@@ -877,13 +966,15 @@ async function spawnChildEngine(req, inherit, runCtx, deps) {
|
|
|
877
966
|
...deps.parentSandbox !== undefined ? { sandbox: deps.parentSandbox } : {},
|
|
878
967
|
...req.definition?.maxTurns !== undefined ? { maxTurns: req.definition.maxTurns } : {},
|
|
879
968
|
...req.outputFormat !== undefined ? { outputFormat: req.outputFormat } : {},
|
|
880
|
-
...inherit.outputStyle !== undefined ? { outputStyle: inherit.outputStyle } : {}
|
|
881
|
-
...hasChildScopedMcpServers ? { mcpServers: childScopedMcpServers } : {}
|
|
969
|
+
...inherit.outputStyle !== undefined ? { outputStyle: inherit.outputStyle } : {}
|
|
882
970
|
};
|
|
883
971
|
const initialMessages = buildForkInitialMessages(inherit, req.parentToolUseId);
|
|
884
972
|
const resolvedSystemPrompt = [inherit.systemPrompt, req.fork === true ? undefined : req.definition?.prompt].filter((s) => s !== undefined && s.length > 0).join(`
|
|
885
973
|
|
|
886
974
|
`);
|
|
975
|
+
let serverAllocation = allocateChildScopedServers(childScopedMcpServers, parentVisibleServers(), undefined, parentMcp?.declaredServers);
|
|
976
|
+
pendingServerRelease = serverAllocation.release;
|
|
977
|
+
definitionWarnings.push(...serverAllocation.notes);
|
|
887
978
|
const firstTurnText = req.fork === true ? buildForkDirectiveText({ prompt: req.prompt, ...req.isolation === "worktree" ? { worktree: { parentRoot: inherit.sessionRoot, worktreeRoot: workspace.root } } : {} }) : [req.definition?.initialPrompt, req.prompt, definitionWarnings.length > 0 ? `
|
|
888
979
|
[winter: ${definitionWarnings.join("; ")}]` : undefined].filter((s) => s !== undefined && s.length > 0).join(`
|
|
889
980
|
|
|
@@ -987,7 +1078,18 @@ async function spawnChildEngine(req, inherit, runCtx, deps) {
|
|
|
987
1078
|
writer?.writeMetadata({ ...record });
|
|
988
1079
|
}
|
|
989
1080
|
record.status = "running";
|
|
990
|
-
|
|
1081
|
+
const previous = serverAllocation.actual;
|
|
1082
|
+
const ticket = { stopped: false };
|
|
1083
|
+
pendingResume = ticket;
|
|
1084
|
+
await Promise.race([lastGenerationDone, new Promise((resolve) => setTimeout(resolve, GENERATION_TEARDOWN_WAIT_MS).unref?.())]);
|
|
1085
|
+
pendingResume = undefined;
|
|
1086
|
+
if (ticket.stopped)
|
|
1087
|
+
return { status: "unavailable", messageId: msg.messageId, retryable: false, reason: `child ${agentId} was stopped while resuming` };
|
|
1088
|
+
serverAllocation = allocateChildScopedServers(childScopedMcpServers, parentVisibleServers(), previous, parentMcp?.declaredServers);
|
|
1089
|
+
const moved = [...serverAllocation.actual].filter(([declared, name]) => previous.get(declared) !== name).map(([declared, name]) => `this agent's own "${declared}" is now connected as "${name}" (its tools are named mcp__${name}__<tool>)`);
|
|
1090
|
+
startGeneration(generationConfig(resumeMode), rebuilt, moved.length > 0 ? `${msg.body}
|
|
1091
|
+
|
|
1092
|
+
[winter: ${moved.join("; ")}]` : msg.body, resolvedSystemPrompt, serverAllocation);
|
|
991
1093
|
return { status: "resumed_and_delivered", messageId: msg.messageId };
|
|
992
1094
|
},
|
|
993
1095
|
async result() {
|
|
@@ -996,6 +1098,12 @@ async function spawnChildEngine(req, inherit, runCtx, deps) {
|
|
|
996
1098
|
async stop() {
|
|
997
1099
|
if (record.status !== "running")
|
|
998
1100
|
return;
|
|
1101
|
+
if (pendingResume !== undefined) {
|
|
1102
|
+
pendingResume.stopped = true;
|
|
1103
|
+
record.status = "stopped";
|
|
1104
|
+
writer?.writeMetadata({ ...record });
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
999
1107
|
currentSettle?.("stopped", "stopped by request");
|
|
1000
1108
|
},
|
|
1001
1109
|
usage() {
|
|
@@ -1005,12 +1113,14 @@ async function spawnChildEngine(req, inherit, runCtx, deps) {
|
|
|
1005
1113
|
try {
|
|
1006
1114
|
req.onSpawned?.(handle);
|
|
1007
1115
|
} catch {}
|
|
1008
|
-
startGeneration(generationConfig(inherit.policy.effectiveMode), initialMessages, firstTurnText, resolvedSystemPrompt);
|
|
1116
|
+
startGeneration(generationConfig(inherit.policy.effectiveMode), initialMessages, firstTurnText, resolvedSystemPrompt, serverAllocation);
|
|
1009
1117
|
spawnRegistered = false;
|
|
1118
|
+
pendingServerRelease = undefined;
|
|
1010
1119
|
return handle;
|
|
1011
1120
|
} catch (err) {
|
|
1012
1121
|
if (spawnRegistered)
|
|
1013
1122
|
releaseSpawn(agentId);
|
|
1123
|
+
pendingServerRelease?.();
|
|
1014
1124
|
throw err;
|
|
1015
1125
|
}
|
|
1016
1126
|
}
|
|
@@ -1305,7 +1415,8 @@ async function foldProviderStream(stream, sink) {
|
|
|
1305
1415
|
...event.cacheWriteTokens !== undefined ? { cacheWriteTokens: event.cacheWriteTokens } : {},
|
|
1306
1416
|
...event.cacheWrite1hTokens !== undefined ? { cacheWrite1hTokens: event.cacheWrite1hTokens } : {},
|
|
1307
1417
|
...event.cacheMiss !== undefined ? { cacheMiss: event.cacheMiss } : {},
|
|
1308
|
-
...event.thinkingBlocksDropped !== undefined ? { thinkingBlocksDropped: event.thinkingBlocksDropped } : {}
|
|
1418
|
+
...event.thinkingBlocksDropped !== undefined ? { thinkingBlocksDropped: event.thinkingBlocksDropped } : {},
|
|
1419
|
+
...event.reasoningTokens !== undefined ? { reasoningTokens: event.reasoningTokens } : {}
|
|
1309
1420
|
};
|
|
1310
1421
|
break;
|
|
1311
1422
|
case "retry":
|
|
@@ -1902,7 +2013,8 @@ function buildSessionProvider(opts) {
|
|
|
1902
2013
|
classifier = createModelClassifier2({
|
|
1903
2014
|
provider: buildProvider(classifierResolved, classifierRouteRaw.authRef !== undefined ? { authRef: classifierRouteRaw.authRef } : {}),
|
|
1904
2015
|
model: classifierResolved.providerModelId,
|
|
1905
|
-
...config.brand !== undefined ? { instructionsFile: config.brand.instructionsFile } : {}
|
|
2016
|
+
...config.brand !== undefined ? { instructionsFile: config.brand.instructionsFile } : {},
|
|
2017
|
+
forcedToolChoiceUnsupported: classifierResolved.descriptor?.unsupportedParameters.includes("tool_choice.tool") === true
|
|
1906
2018
|
});
|
|
1907
2019
|
} catch (err) {
|
|
1908
2020
|
classifier = undefined;
|
|
@@ -1915,7 +2027,8 @@ function buildSessionProvider(opts) {
|
|
|
1915
2027
|
classifier = createModelClassifier2({
|
|
1916
2028
|
provider: buildProvider(resolved),
|
|
1917
2029
|
model: resolved.providerModelId,
|
|
1918
|
-
...config.brand !== undefined ? { instructionsFile: config.brand.instructionsFile } : {}
|
|
2030
|
+
...config.brand !== undefined ? { instructionsFile: config.brand.instructionsFile } : {},
|
|
2031
|
+
forcedToolChoiceUnsupported: resolved.descriptor?.unsupportedParameters.includes("tool_choice.tool") === true
|
|
1919
2032
|
});
|
|
1920
2033
|
classifierIdentity = { modelKey: resolved.modelKey };
|
|
1921
2034
|
}
|
|
@@ -3009,55 +3122,6 @@ function memoryDirFor(input) {
|
|
|
3009
3122
|
return join6(input.storeHome ?? input.home, "projects", memoryProjectKeyFor(input.cwd, input.env), "memory");
|
|
3010
3123
|
}
|
|
3011
3124
|
|
|
3012
|
-
// src/context/plan-mode.ts
|
|
3013
|
-
import { DEFAULT_PLANS_DIRECTORY } from "@yanlinglabs/winter-agent-sdk";
|
|
3014
|
-
var PLAN_MODE_ENFORCEMENT = [
|
|
3015
|
-
"This session is in PLAN MODE. Writes are withheld: file edits, file creation and state-changing shell commands are refused by the permission engine until the plan is approved. This is enforcement, not etiquette — attempting one wastes a turn and changes nothing.",
|
|
3016
|
-
"Reading is unrestricted. Investigate as thoroughly as the plan needs: read files, search, run read-only commands, and inspect whatever settles an open question."
|
|
3017
|
-
].join(`
|
|
3018
|
-
|
|
3019
|
-
`);
|
|
3020
|
-
var DEFAULT_PLAN_BODY = [
|
|
3021
|
-
"Produce a plan the user can approve or correct without having to guess what you intend.",
|
|
3022
|
-
"Ground it in what you actually found. A plan that names the real files, the real functions and the real call sites is reviewable; one written from assumption is a proposal to find out later.",
|
|
3023
|
-
"Say what will change and where, in the order it will happen, and name anything you deliberately are NOT changing when a reader might expect otherwise.",
|
|
3024
|
-
"Call out the parts that are irreversible, that touch data, or that you are least sure about — those are the parts the user is being asked to approve.",
|
|
3025
|
-
"Keep it proportionate. A one-file change needs a short paragraph, not a document; a migration needs the detail.",
|
|
3026
|
-
"If investigation shows the request cannot work as stated, say so and propose the alternative instead of planning around the problem."
|
|
3027
|
-
].join(`
|
|
3028
|
-
|
|
3029
|
-
`);
|
|
3030
|
-
var PLAN_MODE_PROTOCOL = [
|
|
3031
|
-
"When the plan is ready, present it and call the `ExitPlanMode` tool with it. Do not begin implementing first: leaving plan mode is the user's decision, and the tool call is how you ask for it.",
|
|
3032
|
-
"If the user responds with corrections rather than approval, revise the plan and ask again — you are still in plan mode until they say otherwise."
|
|
3033
|
-
].join(`
|
|
3034
|
-
|
|
3035
|
-
`);
|
|
3036
|
-
var PLANS_DIRECTORY_MAX_CHARS = 200;
|
|
3037
|
-
var PLANS_DIRECTORY_PATTERN = /^[A-Za-z0-9 ._~/-]+$/;
|
|
3038
|
-
function renderablePlansDirectory(raw, fallback) {
|
|
3039
|
-
if (raw.length === 0 || raw.length > PLANS_DIRECTORY_MAX_CHARS)
|
|
3040
|
-
return fallback;
|
|
3041
|
-
if (!PLANS_DIRECTORY_PATTERN.test(raw))
|
|
3042
|
-
return fallback;
|
|
3043
|
-
if (raw.trim().length === 0)
|
|
3044
|
-
return fallback;
|
|
3045
|
-
return raw;
|
|
3046
|
-
}
|
|
3047
|
-
function renderPlanModeBlock(input) {
|
|
3048
|
-
const host = input.hostPlanBody?.trim();
|
|
3049
|
-
const body = host === undefined || host.length === 0 ? DEFAULT_PLAN_BODY : host;
|
|
3050
|
-
return [
|
|
3051
|
-
"## Plan mode",
|
|
3052
|
-
PLAN_MODE_ENFORCEMENT,
|
|
3053
|
-
body,
|
|
3054
|
-
PLAN_MODE_PROTOCOL,
|
|
3055
|
-
`If the user asks for the plan as a file, write it under ${renderablePlansDirectory(input.plansDirectory, input.plansDirectoryFallback ?? DEFAULT_PLANS_DIRECTORY)}.`
|
|
3056
|
-
].join(`
|
|
3057
|
-
|
|
3058
|
-
`);
|
|
3059
|
-
}
|
|
3060
|
-
|
|
3061
3125
|
// src/context/assembler.ts
|
|
3062
3126
|
function isPresetOption(value) {
|
|
3063
3127
|
return typeof value === "object" && value !== null && !Array.isArray(value) && value.type === "preset";
|
|
@@ -3145,11 +3209,6 @@ function createSystemPromptAssembler(deps = {}) {
|
|
|
3145
3209
|
...region.callerDynamicBlocks,
|
|
3146
3210
|
styleBody,
|
|
3147
3211
|
input.agentPrompt,
|
|
3148
|
-
input.planMode ? renderPlanModeBlock({
|
|
3149
|
-
plansDirectory: config.plansDirectory ?? settings?.plansDirectory ?? `${brand.projectDirName}/plans`,
|
|
3150
|
-
plansDirectoryFallback: `${brand.projectDirName}/plans`,
|
|
3151
|
-
...input.hostPlanBody !== undefined ? { hostPlanBody: input.hostPlanBody } : {}
|
|
3152
|
-
}) : undefined,
|
|
3153
3212
|
region.excludeDynamicSections || memoryDir === undefined ? undefined : renderAutoMemorySection(memoryDir, brand.instructionsFile),
|
|
3154
3213
|
region.excludeDynamicSections ? undefined : renderEnvironmentSection(environment)
|
|
3155
3214
|
];
|
|
@@ -3208,6 +3267,15 @@ function createSystemPromptAssembler(deps = {}) {
|
|
|
3208
3267
|
entries.push(["auto memory", renderAutoMemoryContextValue(memoryDir, brand.instructionsFile)]);
|
|
3209
3268
|
}
|
|
3210
3269
|
return entries;
|
|
3270
|
+
},
|
|
3271
|
+
planModeInput(input) {
|
|
3272
|
+
const config = input.config;
|
|
3273
|
+
const { settings, brand } = resolveContext(deps, input);
|
|
3274
|
+
return {
|
|
3275
|
+
plansDirectory: config.plansDirectory ?? settings?.plansDirectory ?? `${brand.projectDirName}/plans`,
|
|
3276
|
+
plansDirectoryFallback: `${brand.projectDirName}/plans`,
|
|
3277
|
+
...input.hostPlanBody !== undefined ? { hostPlanBody: input.hostPlanBody } : {}
|
|
3278
|
+
};
|
|
3211
3279
|
}
|
|
3212
3280
|
};
|
|
3213
3281
|
}
|
|
@@ -5384,7 +5452,8 @@ function describeCatalogModel(catalog, model, providerId) {
|
|
|
5384
5452
|
...row.inlineToolDefinitions !== undefined ? { toolChanges: "inline" } : row.midConversationToolChanges !== undefined ? { toolChanges: "reference" } : {},
|
|
5385
5453
|
...row.clientToolSearch?.value === true ? { clientToolSearch: true } : {},
|
|
5386
5454
|
...row.additionalToolsItem?.value === true ? { additionalToolsItem: true } : {},
|
|
5387
|
-
...row.allowedToolsChoice?.value === true ? { allowedToolsChoice: true } : {}
|
|
5455
|
+
...row.allowedToolsChoice?.value === true ? { allowedToolsChoice: true } : {},
|
|
5456
|
+
...row.undeclaredToolCalls?.value === true ? { undeclaredToolCalls: true } : {}
|
|
5388
5457
|
};
|
|
5389
5458
|
const description = {
|
|
5390
5459
|
...row.displayName.length > 0 ? { displayName: row.displayName } : {},
|