newmark-agent 0.4.6 → 0.4.8
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/assets/app-icon-dark.svg +6 -0
- package/dist/assets/app-icon-dark.svg +6 -0
- package/dist/cli-commands.js +2 -1
- package/dist/cli-discovery.js +2 -0
- package/dist/conversation-utility-host.bundle.cjs +577 -166
- package/dist/conversation-utility-host.js +3 -0
- package/dist/core/agent.d.ts +40 -4
- package/dist/core/agent.js +251 -49
- package/dist/core/agentKernelRunner.d.ts +3 -0
- package/dist/core/agentKernelRunner.js +74 -91
- package/dist/core/config.js +1 -1
- package/dist/core/conversationKernel.d.ts +40 -0
- package/dist/core/conversationKernel.js +219 -8
- package/dist/core/electronUtilityAgentClient.d.ts +8 -0
- package/dist/core/electronUtilityAgentClient.js +5 -1
- package/dist/core/electronUtilityRuntimePool.d.ts +15 -0
- package/dist/core/electronUtilityRuntimePool.js +11 -0
- package/dist/core/installUpdate.js +11 -8
- package/dist/core/mobilePairing.d.ts +1 -0
- package/dist/core/mobilePairing.js +15 -1
- package/dist/core/subagent.d.ts +10 -3
- package/dist/core/subagent.js +23 -8
- package/dist/core/toolPolicy.js +14 -3
- package/dist/core/utilityAgentProtocol.d.ts +29 -1
- package/dist/core/utilityHostToolRouter.js +18 -0
- package/dist/core/wslAgentClient.d.ts +8 -0
- package/dist/core/wslAgentClient.js +5 -1
- package/dist/core/wslAgentProtocol.d.ts +18 -1
- package/dist/core/wslAgentRuntimePool.d.ts +15 -0
- package/dist/core/wslAgentRuntimePool.js +11 -0
- package/dist/launcher.js +14 -11
- package/dist/main.js +207 -9
- package/dist/providers/chat-completions.adapter.js +6 -2
- package/dist/providers/responses.adapter.js +1 -0
- package/dist/server.d.ts +33 -1
- package/dist/server.js +696 -48
- package/dist/toolchain/registry-seeder.js +3 -1
- package/dist/tools/index.js +57 -6
- package/dist/tools/nativeTools.js +2 -1
- package/dist/ui/index.html +88 -101
- package/dist/wsl-agent-host.bundle.cjs +577 -166
- package/dist/wsl-agent-host.js +3 -0
- package/package.json +4 -2
|
@@ -79,6 +79,9 @@ async function handle(request) {
|
|
|
79
79
|
target,
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
+
if (request.method === 'queue_action') {
|
|
83
|
+
return kernel.queueAction(checkedTarget(request.params.target), request.params.action, request.params.input);
|
|
84
|
+
}
|
|
82
85
|
if (request.method === 'checkpoint')
|
|
83
86
|
return kernel.checkpoint(checkedTarget(request.params.target));
|
|
84
87
|
if (request.method === 'context_compress') {
|
package/dist/core/agent.d.ts
CHANGED
|
@@ -346,6 +346,7 @@ export declare class Agent {
|
|
|
346
346
|
private memoryLabRebuildState;
|
|
347
347
|
private memoryLabRebuildError;
|
|
348
348
|
private displayImageDescriptionCache;
|
|
349
|
+
private latestCapturedImageInputs;
|
|
349
350
|
private activeProcessAbortController;
|
|
350
351
|
private automationManager;
|
|
351
352
|
private activeAgentKernelRuntime;
|
|
@@ -474,7 +475,9 @@ export declare class Agent {
|
|
|
474
475
|
private workspaceConversationKey;
|
|
475
476
|
private workspaceConversationStorePath;
|
|
476
477
|
private workspaceConversationStateKey;
|
|
478
|
+
private workspaceConversationStateKeyFor;
|
|
477
479
|
private workspaceConversationPrefix;
|
|
480
|
+
private workspaceConversationPrefixFor;
|
|
478
481
|
private safeConversationId;
|
|
479
482
|
subscribeWorkEvents(fn: (event: AgentWorkEvent) => void): () => void;
|
|
480
483
|
subscribePeerWorkEvents(fn: (event: AgentWorkEvent) => void): () => void;
|
|
@@ -620,6 +623,31 @@ export declare class Agent {
|
|
|
620
623
|
order: number;
|
|
621
624
|
branchCommunication: boolean;
|
|
622
625
|
}>;
|
|
626
|
+
registerCapturedImageInput(dataUrl: string, name?: string): ConversationImageAttachment | null;
|
|
627
|
+
private subagentConcurrencyLimit;
|
|
628
|
+
/** 当前工作区使用内存中的前台选择;后台工作区从各自持久化状态读取 active id。 */
|
|
629
|
+
activeConversationIdForWorkspace(ws: WorkspaceInfo | null): string;
|
|
630
|
+
/**
|
|
631
|
+
* 持久化的完整 work run 记录(含 interrupted/force_interrupted)。
|
|
632
|
+
* 不依赖运行时内存(run 结束后内存清空,state 端点曾因此丢失被中断的构建记录),
|
|
633
|
+
* 供 mobile 端点稳定透出完整对话信息;移动端按同一格式解析。
|
|
634
|
+
*/
|
|
635
|
+
getPersistedConversationWorkRuns(conversationId: string, ws?: WorkspaceInfo | null): ConversationWorkRun[];
|
|
636
|
+
/** Exact membership check against the raw persisted state key, before UI content deduplication. */
|
|
637
|
+
hasConversationInWorkspace(conversationId: string, ws: WorkspaceInfo | null): boolean;
|
|
638
|
+
/** 按工作区列对话(任意 ws,key 前缀 = kind-sha256(path).slice(0,16));供 mobile API 透出工作区从属对话 */
|
|
639
|
+
listWorkspaceConversationStates(ws: WorkspaceInfo | null): Array<{
|
|
640
|
+
id: string;
|
|
641
|
+
key: string;
|
|
642
|
+
title: string;
|
|
643
|
+
messageCount: number;
|
|
644
|
+
historyCount: number;
|
|
645
|
+
updatedAt: string;
|
|
646
|
+
pinned: boolean;
|
|
647
|
+
pinnedAt: string;
|
|
648
|
+
order: number;
|
|
649
|
+
branchCommunication: boolean;
|
|
650
|
+
}>;
|
|
623
651
|
private normalizeLinkedPlan;
|
|
624
652
|
private subagentManagerKey;
|
|
625
653
|
private bindConversationSubagents;
|
|
@@ -632,6 +660,7 @@ export declare class Agent {
|
|
|
632
660
|
getConversationSnapshot(conversationId?: string, options?: {
|
|
633
661
|
window?: number;
|
|
634
662
|
before?: number;
|
|
663
|
+
workspace?: WorkspaceInfo | null;
|
|
635
664
|
}): ConversationSnapshot;
|
|
636
665
|
inspectConversationBranch(conversationId: string, branchId: string, branchGroupId?: string): ConversationSnapshot;
|
|
637
666
|
ensureConversationSnapshot(conversationId?: string): ConversationSnapshot;
|
|
@@ -640,8 +669,13 @@ export declare class Agent {
|
|
|
640
669
|
setBranchCommunication(enabled: boolean): boolean;
|
|
641
670
|
isBranchCommunicationEnabled(): boolean;
|
|
642
671
|
switchConversationBranch(conversationId: string, branchId: string, branchGroupId?: string): ConversationSnapshot;
|
|
643
|
-
setConversationPinned(id: string, pinned: boolean): boolean;
|
|
644
|
-
renameConversation(id: string, title: string): boolean;
|
|
672
|
+
setConversationPinned(id: string, pinned: boolean, ws?: WorkspaceInfo | null): boolean;
|
|
673
|
+
renameConversation(id: string, title: string, ws?: WorkspaceInfo | null): boolean;
|
|
674
|
+
/** 为指定工作区创建空白对话,不临时切换全局前台工作区。 */
|
|
675
|
+
createConversationInWorkspace(ws: WorkspaceInfo, title?: string): {
|
|
676
|
+
id: string;
|
|
677
|
+
title: string;
|
|
678
|
+
};
|
|
645
679
|
/**
|
|
646
680
|
* 首 Build 命名判定:仅当 (1) 当前对话尚无历史 Build(排除当前 run)且
|
|
647
681
|
* (2) 其持久化 title 仍是自动生成(含为空)时返回 true。dev-0.4.3 起不再
|
|
@@ -675,6 +709,8 @@ export declare class Agent {
|
|
|
675
709
|
*/
|
|
676
710
|
private maybeAutoRenameConversationFromRun;
|
|
677
711
|
reorderConversations(ids: string[]): boolean;
|
|
712
|
+
/** Reorder one pinned group inside an explicit workspace without changing membership. */
|
|
713
|
+
reorderWorkspaceConversationGroup(ids: string[], ws: WorkspaceInfo | null): boolean;
|
|
678
714
|
flushConversationState(): void;
|
|
679
715
|
private titleFromMessages;
|
|
680
716
|
private hasUserConversationTitle;
|
|
@@ -892,7 +928,7 @@ export declare class Agent {
|
|
|
892
928
|
* large markdown payload and manifest use promise-based filesystem I/O so
|
|
893
929
|
* independent workspaces can archive in parallel without freezing Electron.
|
|
894
930
|
*/
|
|
895
|
-
archiveConversationAsync(conversationId: string): Promise<string | null>;
|
|
931
|
+
archiveConversationAsync(conversationId: string, ws?: WorkspaceInfo | null): Promise<string | null>;
|
|
896
932
|
private archiveConversationAsyncUnlocked;
|
|
897
933
|
private finalizeAsyncConversationArchive;
|
|
898
934
|
private listStoredConversationIds;
|
|
@@ -997,7 +1033,7 @@ export declare class Agent {
|
|
|
997
1033
|
private withTimeout;
|
|
998
1034
|
private normalizeSubagentModelSelection;
|
|
999
1035
|
handleSubagent(args: string): Promise<string>;
|
|
1000
|
-
handleSubagentEnvelope(args: string): Promise<NewmarkSubagentToolResult>;
|
|
1036
|
+
handleSubagentEnvelope(args: string, requireRunningBuild?: boolean): Promise<NewmarkSubagentToolResult>;
|
|
1001
1037
|
private resolveSubagentPreset;
|
|
1002
1038
|
private buildSubagentPrompt;
|
|
1003
1039
|
handleSubagentContinue(args: string): Promise<string>;
|
package/dist/core/agent.js
CHANGED
|
@@ -241,6 +241,7 @@ class Agent {
|
|
|
241
241
|
memoryLabRebuildState = 'idle';
|
|
242
242
|
memoryLabRebuildError = '';
|
|
243
243
|
displayImageDescriptionCache = new Map();
|
|
244
|
+
latestCapturedImageInputs = [];
|
|
244
245
|
activeProcessAbortController = null;
|
|
245
246
|
automationManager = null;
|
|
246
247
|
activeAgentKernelRuntime = null;
|
|
@@ -380,7 +381,7 @@ class Agent {
|
|
|
380
381
|
this.tools = new index_1.ToolExecutor(rootPath, this.config, this.ssh, this.workspace);
|
|
381
382
|
this.skills = new skills_1.SkillsManager(rootPath);
|
|
382
383
|
this.memoryLab = new memoryLab_1.MemoryLabManager(rootPath, this.config.getStr('general', 'language'));
|
|
383
|
-
this.subagents = new subagent_1.SubagentManager({ rootAgentId: this.runtimeActorId });
|
|
384
|
+
this.subagents = new subagent_1.SubagentManager({ rootAgentId: this.runtimeActorId, concurrency: this.subagentConcurrencyLimit() });
|
|
384
385
|
if (this.mode === 'goal' && !this.goal) {
|
|
385
386
|
this.goal = new GoalStateImpl('Set your objective');
|
|
386
387
|
}
|
|
@@ -925,6 +926,7 @@ class Agent {
|
|
|
925
926
|
}
|
|
926
927
|
setIntelligence(tier, persist = false) {
|
|
927
928
|
this.intelligence = normalizeIntelligenceTier(tier);
|
|
929
|
+
this.subagents?.setConcurrencyLimit(this.subagentConcurrencyLimit());
|
|
928
930
|
if (persist) {
|
|
929
931
|
this.config.set('models', 'default_intelligence', this.intelligence);
|
|
930
932
|
this.config.save();
|
|
@@ -1158,13 +1160,18 @@ class Agent {
|
|
|
1158
1160
|
return path.join(ws.path, 'conversations', 'state.json');
|
|
1159
1161
|
}
|
|
1160
1162
|
workspaceConversationStateKey(conversationId = this.activeConversationId) {
|
|
1161
|
-
|
|
1163
|
+
return this.workspaceConversationStateKeyFor(conversationId, this.workspace.current);
|
|
1164
|
+
}
|
|
1165
|
+
workspaceConversationStateKeyFor(conversationId, ws) {
|
|
1166
|
+
const prefix = this.workspaceConversationPrefixFor(ws);
|
|
1162
1167
|
if (!prefix)
|
|
1163
1168
|
return null;
|
|
1164
1169
|
return `${prefix}-${this.safeConversationId(conversationId)}`;
|
|
1165
1170
|
}
|
|
1166
1171
|
workspaceConversationPrefix() {
|
|
1167
|
-
|
|
1172
|
+
return this.workspaceConversationPrefixFor(this.workspace.current);
|
|
1173
|
+
}
|
|
1174
|
+
workspaceConversationPrefixFor(ws) {
|
|
1168
1175
|
if (!ws)
|
|
1169
1176
|
return null;
|
|
1170
1177
|
const supplied = String(ws.conversationStatePrefix || '').trim();
|
|
@@ -2851,8 +2858,62 @@ class Agent {
|
|
|
2851
2858
|
}
|
|
2852
2859
|
}
|
|
2853
2860
|
listConversationStates() {
|
|
2854
|
-
|
|
2855
|
-
|
|
2861
|
+
return this.listWorkspaceConversationStates(this.workspace.current);
|
|
2862
|
+
}
|
|
2863
|
+
registerCapturedImageInput(dataUrl, name = 'active-screenshot.jpg') {
|
|
2864
|
+
if (!String(dataUrl || '').startsWith('data:image/'))
|
|
2865
|
+
return null;
|
|
2866
|
+
const prepared = this.prepareSubmittedConversationImages([{ dataUrl, name, type: dataUrl.slice(5, dataUrl.indexOf(';')) }]);
|
|
2867
|
+
const attachment = prepared.attachments[0] || null;
|
|
2868
|
+
this.latestCapturedImageInputs = attachment ? [attachment] : [];
|
|
2869
|
+
return attachment;
|
|
2870
|
+
}
|
|
2871
|
+
subagentConcurrencyLimit() {
|
|
2872
|
+
return this.intelligence === 'ultra' ? 16 : 4;
|
|
2873
|
+
}
|
|
2874
|
+
/** 当前工作区使用内存中的前台选择;后台工作区从各自持久化状态读取 active id。 */
|
|
2875
|
+
activeConversationIdForWorkspace(ws) {
|
|
2876
|
+
const targetWs = ws || this.workspace.current;
|
|
2877
|
+
if (!targetWs)
|
|
2878
|
+
return 'default';
|
|
2879
|
+
const currentWs = this.workspace.current;
|
|
2880
|
+
const isCurrent = !!currentWs && path.resolve(currentWs.path) === path.resolve(targetWs.path);
|
|
2881
|
+
if (isCurrent)
|
|
2882
|
+
return this.safeConversationId(this.activeConversationId || 'default');
|
|
2883
|
+
const stored = this.readStoredConversationState(targetWs);
|
|
2884
|
+
return this.safeConversationId(stored.activeConversationId || 'default');
|
|
2885
|
+
}
|
|
2886
|
+
/**
|
|
2887
|
+
* 持久化的完整 work run 记录(含 interrupted/force_interrupted)。
|
|
2888
|
+
* 不依赖运行时内存(run 结束后内存清空,state 端点曾因此丢失被中断的构建记录),
|
|
2889
|
+
* 供 mobile 端点稳定透出完整对话信息;移动端按同一格式解析。
|
|
2890
|
+
*/
|
|
2891
|
+
getPersistedConversationWorkRuns(conversationId, ws = null) {
|
|
2892
|
+
const targetWs = ws || this.workspace.current;
|
|
2893
|
+
const clean = this.safeConversationId(conversationId || 'default');
|
|
2894
|
+
const stateKey = this.workspaceConversationStateKeyFor(clean, targetWs);
|
|
2895
|
+
const stored = this.readStoredConversationState(targetWs);
|
|
2896
|
+
const persisted = stateKey && stored.conversations ? stored.conversations[stateKey] : undefined;
|
|
2897
|
+
const tree = persisted ? this.normalizeConversationTree(persisted) : null;
|
|
2898
|
+
const runtimeNodeId = String(tree?.activeNodeId || '');
|
|
2899
|
+
const viewedNodeId = tree
|
|
2900
|
+
? this.resolveConversationTreePath(tree, this.storedConversationTreePath(tree, persisted?.viewedBranchNodePath, runtimeNodeId))
|
|
2901
|
+
: '';
|
|
2902
|
+
const viewedNode = tree?.nodes[viewedNodeId];
|
|
2903
|
+
return this.normalizeWorkRuns(viewedNode?.workRuns || persisted?.workRuns);
|
|
2904
|
+
}
|
|
2905
|
+
/** Exact membership check against the raw persisted state key, before UI content deduplication. */
|
|
2906
|
+
hasConversationInWorkspace(conversationId, ws) {
|
|
2907
|
+
const targetWs = ws || this.workspace.current;
|
|
2908
|
+
const stateKey = this.workspaceConversationStateKeyFor(this.safeConversationId(conversationId || 'default'), targetWs);
|
|
2909
|
+
if (!stateKey)
|
|
2910
|
+
return false;
|
|
2911
|
+
return Object.prototype.hasOwnProperty.call(this.readStoredConversationState(targetWs).conversations || {}, stateKey);
|
|
2912
|
+
}
|
|
2913
|
+
/** 按工作区列对话(任意 ws,key 前缀 = kind-sha256(path).slice(0,16));供 mobile API 透出工作区从属对话 */
|
|
2914
|
+
listWorkspaceConversationStates(ws) {
|
|
2915
|
+
const stored = this.readStoredConversationState(ws);
|
|
2916
|
+
const prefix = this.workspaceConversationPrefixFor(ws) || '';
|
|
2856
2917
|
const scopedEntries = Object.entries(stored.conversations || {}).filter(([key]) => !prefix || key.startsWith(prefix));
|
|
2857
2918
|
if (scopedEntries.some(([, value]) => !Number.isFinite(value.order))) {
|
|
2858
2919
|
const legacyOrder = [...scopedEntries].sort(([, a], [, b]) => {
|
|
@@ -2863,7 +2924,7 @@ class Agent {
|
|
|
2863
2924
|
return String(b.updatedAt || '').localeCompare(String(a.updatedAt || ''));
|
|
2864
2925
|
});
|
|
2865
2926
|
legacyOrder.forEach(([, value], index) => { value.order = index; });
|
|
2866
|
-
this.writeStoredConversationState(stored);
|
|
2927
|
+
this.writeStoredConversationState(stored, ws);
|
|
2867
2928
|
}
|
|
2868
2929
|
const rows = [];
|
|
2869
2930
|
for (const [key, value] of Object.entries(stored.conversations || {})) {
|
|
@@ -2922,6 +2983,7 @@ class Agent {
|
|
|
2922
2983
|
this.subagents = (0, subagent_1.sharedSubagentManager)(this.subagentManagerKey(clean), {
|
|
2923
2984
|
conversationId: clean,
|
|
2924
2985
|
rootAgentId: state?.rootAgentId || this.runtimeActorId,
|
|
2986
|
+
concurrency: this.subagentConcurrencyLimit(),
|
|
2925
2987
|
state,
|
|
2926
2988
|
executor: job => this.runSubagentJob(job.record.id, job.prompt, job.flowName, job.reason),
|
|
2927
2989
|
persist: subagentState => this.persistSubagentState(clean, subagentState),
|
|
@@ -2995,16 +3057,18 @@ class Agent {
|
|
|
2995
3057
|
}
|
|
2996
3058
|
getConversationSnapshot(conversationId = this.activeConversationId, options = {}) {
|
|
2997
3059
|
const clean = this.safeConversationId(conversationId || 'default');
|
|
2998
|
-
const
|
|
2999
|
-
const
|
|
3000
|
-
const
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3060
|
+
const ws = options.workspace || this.workspace.current;
|
|
3061
|
+
const currentWs = this.workspace.current;
|
|
3062
|
+
const isActiveWorkspace = (!ws && !currentWs)
|
|
3063
|
+
|| (!!ws && !!currentWs && path.resolve(ws.path) === path.resolve(currentWs.path));
|
|
3064
|
+
const isActiveConversation = isActiveWorkspace
|
|
3065
|
+
&& clean === this.safeConversationId(this.activeConversationId || 'default');
|
|
3066
|
+
const stateKey = this.workspaceConversationStateKeyFor(clean, ws);
|
|
3067
|
+
const memoryKey = ws
|
|
3068
|
+
? `${ws.isInternal ? 'internal' : 'external'}:${path.resolve(ws.path)}::conversation:${clean}`
|
|
3069
|
+
: null;
|
|
3006
3070
|
const memory = memoryKey ? this.workspaceConversations.get(memoryKey) : undefined;
|
|
3007
|
-
const stored = this.readStoredConversationState();
|
|
3071
|
+
const stored = this.readStoredConversationState(ws);
|
|
3008
3072
|
const persisted = stateKey && stored.conversations ? stored.conversations[stateKey] : undefined;
|
|
3009
3073
|
const tree = persisted ? this.normalizeConversationTree(persisted) : null;
|
|
3010
3074
|
const runtimeNodeId = String(tree?.activeNodeId || '');
|
|
@@ -3039,7 +3103,7 @@ class Agent {
|
|
|
3039
3103
|
const continuations = this.normalizeContinuations(isActiveConversation && viewingRuntimeNode ? this.continuations : (viewedNode?.continuations || persisted?.continuations || memory?.continuations));
|
|
3040
3104
|
return {
|
|
3041
3105
|
conversationId: clean,
|
|
3042
|
-
conversations: this.
|
|
3106
|
+
conversations: this.listWorkspaceConversationStates(ws),
|
|
3043
3107
|
conversationPlan: this.normalizeConversationPlan(isActiveConversation ? this.conversationPlan : (persisted?.plan || memory?.plan)),
|
|
3044
3108
|
linkedPlan: this.normalizeLinkedPlan(isActiveConversation ? this.linkedPlan : (persisted?.linkedPlan || memory?.linkedPlan)),
|
|
3045
3109
|
subagents: this.recordsForState(isActiveConversation ? this.subagents.serialize() : (persisted?.subagentState || memory?.subagentState)),
|
|
@@ -3051,11 +3115,11 @@ class Agent {
|
|
|
3051
3115
|
continuations,
|
|
3052
3116
|
modelSelection: isActiveConversation
|
|
3053
3117
|
? this.currentConversationModelSelection()
|
|
3054
|
-
: (persisted?.modelSelection || memory?.modelSelection ||
|
|
3118
|
+
: (persisted?.modelSelection || memory?.modelSelection || { kind: 'auto' }),
|
|
3055
3119
|
flowSelection: isActiveConversation
|
|
3056
3120
|
? this.currentConversationFlowSelection()
|
|
3057
3121
|
: (persisted?.flowSelection || memory?.flowSelection || null),
|
|
3058
|
-
inputMode: this.inputMode,
|
|
3122
|
+
inputMode: isActiveConversation ? this.inputMode : (persisted?.inputMode || memory?.inputMode || 'guide'),
|
|
3059
3123
|
mode: isActiveConversation ? this.mode : (persisted?.mode || memory?.mode || 'build'),
|
|
3060
3124
|
goal: isActiveConversation ? this.serializeGoal() : (persisted?.goal || memory?.goal || null),
|
|
3061
3125
|
branches: this.branchGroupMetadata(tree),
|
|
@@ -3388,13 +3452,19 @@ class Agent {
|
|
|
3388
3452
|
this.setConversationFromStorage(clean);
|
|
3389
3453
|
return this.getConversationSnapshot(clean);
|
|
3390
3454
|
}
|
|
3391
|
-
setConversationPinned(id, pinned) {
|
|
3455
|
+
setConversationPinned(id, pinned, ws = this.workspace.current) {
|
|
3456
|
+
const targetWs = ws || this.workspace.current;
|
|
3457
|
+
if (!targetWs)
|
|
3458
|
+
return false;
|
|
3392
3459
|
const clean = this.safeConversationId(id || 'default');
|
|
3393
|
-
this.
|
|
3394
|
-
const
|
|
3460
|
+
const currentWs = this.workspace.current;
|
|
3461
|
+
const isCurrent = !!currentWs && path.resolve(currentWs.path) === path.resolve(targetWs.path);
|
|
3462
|
+
if (isCurrent)
|
|
3463
|
+
this.saveWorkspaceConversationState();
|
|
3464
|
+
const stateKey = this.workspaceConversationStateKeyFor(clean, targetWs);
|
|
3395
3465
|
if (!stateKey)
|
|
3396
3466
|
return false;
|
|
3397
|
-
const stored = this.readStoredConversationState();
|
|
3467
|
+
const stored = this.readStoredConversationState(targetWs);
|
|
3398
3468
|
stored.conversations = stored.conversations || {};
|
|
3399
3469
|
const existing = stored.conversations[stateKey];
|
|
3400
3470
|
if (!existing)
|
|
@@ -3406,26 +3476,72 @@ class Agent {
|
|
|
3406
3476
|
.map(([, value]) => Number(value.order));
|
|
3407
3477
|
existing.order = siblingOrders.length ? Math.min(...siblingOrders) - 1 : 0;
|
|
3408
3478
|
existing.updatedAt = existing.updatedAt || new Date().toISOString();
|
|
3409
|
-
this.writeStoredConversationState(stored);
|
|
3479
|
+
this.writeStoredConversationState(stored, targetWs);
|
|
3410
3480
|
return true;
|
|
3411
3481
|
}
|
|
3412
|
-
renameConversation(id, title) {
|
|
3482
|
+
renameConversation(id, title, ws = this.workspace.current) {
|
|
3483
|
+
const targetWs = ws || this.workspace.current;
|
|
3484
|
+
if (!targetWs)
|
|
3485
|
+
return false;
|
|
3413
3486
|
const clean = this.safeConversationId(id || 'default');
|
|
3414
3487
|
const nextTitle = String(title || '').replace(/\s+/g, ' ').trim().slice(0, 80);
|
|
3415
3488
|
if (!nextTitle)
|
|
3416
3489
|
return false;
|
|
3417
|
-
this.
|
|
3418
|
-
const
|
|
3490
|
+
const currentWs = this.workspace.current;
|
|
3491
|
+
const isCurrent = !!currentWs && path.resolve(currentWs.path) === path.resolve(targetWs.path);
|
|
3492
|
+
if (isCurrent)
|
|
3493
|
+
this.saveWorkspaceConversationState();
|
|
3494
|
+
const stateKey = this.workspaceConversationStateKeyFor(clean, targetWs);
|
|
3419
3495
|
if (!stateKey)
|
|
3420
3496
|
return false;
|
|
3421
|
-
const stored = this.readStoredConversationState();
|
|
3497
|
+
const stored = this.readStoredConversationState(targetWs);
|
|
3422
3498
|
const existing = stored.conversations?.[stateKey];
|
|
3423
3499
|
if (!existing)
|
|
3424
3500
|
return false;
|
|
3425
3501
|
existing.title = nextTitle;
|
|
3426
|
-
this.writeStoredConversationState(stored);
|
|
3502
|
+
this.writeStoredConversationState(stored, targetWs);
|
|
3427
3503
|
return true;
|
|
3428
3504
|
}
|
|
3505
|
+
/** 为指定工作区创建空白对话,不临时切换全局前台工作区。 */
|
|
3506
|
+
createConversationInWorkspace(ws, title = '') {
|
|
3507
|
+
const existing = this.listWorkspaceConversationStates(ws);
|
|
3508
|
+
const id = this.safeConversationId(`conv-${Date.now()}-${crypto.randomUUID().slice(0, 8)}`);
|
|
3509
|
+
const resolvedTitle = String(title || '').replace(/\s+/g, ' ').trim().slice(0, 80)
|
|
3510
|
+
|| `New chat ${existing.length + 1}`;
|
|
3511
|
+
const stateKey = this.workspaceConversationStateKeyFor(id, ws);
|
|
3512
|
+
if (!stateKey)
|
|
3513
|
+
throw new Error('Conversation workspace is unavailable.');
|
|
3514
|
+
const unpinnedOrders = existing.filter(item => !item.pinned).map(item => Number(item.order || 0));
|
|
3515
|
+
const order = unpinnedOrders.length ? Math.min(...unpinnedOrders) - 1 : 0;
|
|
3516
|
+
const now = new Date().toISOString();
|
|
3517
|
+
this.mutateStoredConversationState(ws, latest => {
|
|
3518
|
+
latest.version = 3;
|
|
3519
|
+
latest.activeConversationId = id;
|
|
3520
|
+
latest.conversations = latest.conversations || {};
|
|
3521
|
+
latest.conversations[stateKey] = {
|
|
3522
|
+
title: resolvedTitle,
|
|
3523
|
+
chatMessages: [],
|
|
3524
|
+
history: [],
|
|
3525
|
+
plan: { items: [] },
|
|
3526
|
+
linkedPlan: { markdown: '', revision: 0 },
|
|
3527
|
+
workRuns: [],
|
|
3528
|
+
continuations: [],
|
|
3529
|
+
inputMode: this.defaultInputMode(),
|
|
3530
|
+
mode: 'build',
|
|
3531
|
+
updatedAt: now,
|
|
3532
|
+
pinned: false,
|
|
3533
|
+
pinnedAt: '',
|
|
3534
|
+
order,
|
|
3535
|
+
branchCommunication: false,
|
|
3536
|
+
};
|
|
3537
|
+
return latest;
|
|
3538
|
+
});
|
|
3539
|
+
const currentWs = this.workspace.current;
|
|
3540
|
+
if (currentWs && path.resolve(currentWs.path) === path.resolve(ws.path)) {
|
|
3541
|
+
this.setConversationFromStorage(id);
|
|
3542
|
+
}
|
|
3543
|
+
return { id, title: resolvedTitle };
|
|
3544
|
+
}
|
|
3429
3545
|
/**
|
|
3430
3546
|
* 首 Build 命名判定:仅当 (1) 当前对话尚无历史 Build(排除当前 run)且
|
|
3431
3547
|
* (2) 其持久化 title 仍是自动生成(含为空)时返回 true。dev-0.4.3 起不再
|
|
@@ -3560,6 +3676,39 @@ class Agent {
|
|
|
3560
3676
|
this.writeStoredConversationState(stored);
|
|
3561
3677
|
return true;
|
|
3562
3678
|
}
|
|
3679
|
+
/** Reorder one pinned group inside an explicit workspace without changing membership. */
|
|
3680
|
+
reorderWorkspaceConversationGroup(ids, ws) {
|
|
3681
|
+
const targetWs = ws || this.workspace.current;
|
|
3682
|
+
if (!targetWs || !Array.isArray(ids) || ids.length < 2)
|
|
3683
|
+
return false;
|
|
3684
|
+
const normalized = ids.map(id => this.safeConversationId(String(id || '')));
|
|
3685
|
+
if (normalized.some(id => !id) || new Set(normalized).size !== normalized.length)
|
|
3686
|
+
return false;
|
|
3687
|
+
const currentWs = this.workspace.current;
|
|
3688
|
+
const isCurrent = !!currentWs && path.resolve(currentWs.path) === path.resolve(targetWs.path);
|
|
3689
|
+
if (isCurrent)
|
|
3690
|
+
this.saveWorkspaceConversationState();
|
|
3691
|
+
let accepted = false;
|
|
3692
|
+
this.mutateStoredConversationState(targetWs, latest => {
|
|
3693
|
+
const prefix = this.workspaceConversationPrefixFor(targetWs) || '';
|
|
3694
|
+
const entries = Object.entries(latest.conversations || {})
|
|
3695
|
+
.filter(([key]) => !prefix || key.startsWith(prefix));
|
|
3696
|
+
const entryById = new Map(entries.map(([key, value]) => [key.slice(prefix.length + 1) || key, value]));
|
|
3697
|
+
const requested = normalized.map(id => entryById.get(id));
|
|
3698
|
+
if (requested.some(entry => !entry))
|
|
3699
|
+
return latest;
|
|
3700
|
+
if (new Set(requested.map(entry => !!entry.pinned)).size !== 1)
|
|
3701
|
+
return latest;
|
|
3702
|
+
const orderSlots = requested.map(entry => Number(entry.order));
|
|
3703
|
+
if (orderSlots.some(order => !Number.isFinite(order)))
|
|
3704
|
+
return latest;
|
|
3705
|
+
orderSlots.sort((a, b) => a - b);
|
|
3706
|
+
normalized.forEach((id, index) => { entryById.get(id).order = orderSlots[index]; });
|
|
3707
|
+
accepted = true;
|
|
3708
|
+
return latest;
|
|
3709
|
+
});
|
|
3710
|
+
return accepted;
|
|
3711
|
+
}
|
|
3563
3712
|
flushConversationState() {
|
|
3564
3713
|
this.saveWorkspaceConversationState();
|
|
3565
3714
|
}
|
|
@@ -5678,17 +5827,17 @@ class Agent {
|
|
|
5678
5827
|
this.saveWorkspaceConversationState(true);
|
|
5679
5828
|
return { text, hiddenUserInput: true, goalContinuation: true };
|
|
5680
5829
|
}
|
|
5681
|
-
buildSessionArchive(messages,
|
|
5830
|
+
buildSessionArchive(messages, context, archiveDir) {
|
|
5682
5831
|
const stamp = new Date().toISOString().replace(/[:.]/g, '').replace('T', '_').replace('Z', '');
|
|
5683
5832
|
// Millisecond-only names collide when a user clicks several archive
|
|
5684
5833
|
// buttons in one event-loop turn. Keep the readable timestamp and add a
|
|
5685
5834
|
// cryptographic suffix so every request owns an independent file.
|
|
5686
5835
|
const filename = `session_${stamp}_${crypto.randomUUID().slice(0, 8)}.md`;
|
|
5687
5836
|
let markdown = `# Newmark Session — ${stamp}\n\n`;
|
|
5688
|
-
markdown += `**Mode**: ${mode}\n**Model**: ${model}\n`;
|
|
5837
|
+
markdown += `**Mode**: ${context.mode}\n**Model**: ${context.model}\n`;
|
|
5689
5838
|
markdown += `**Messages**: ${messages.length}\n\n---\n\n`;
|
|
5690
|
-
if (
|
|
5691
|
-
markdown += `**Goal**: ${
|
|
5839
|
+
if (context.goal?.objective)
|
|
5840
|
+
markdown += `**Goal**: ${context.goal.objective}\n\n`;
|
|
5692
5841
|
for (const msg of messages) {
|
|
5693
5842
|
markdown += `**[${msg.role}] ${msg.timestamp}**\n\n${msg.content}\n\n`;
|
|
5694
5843
|
for (const attachment of (0, conversationAttachments_1.hydrateConversationImageAttachments)(this.rootPath, msg.attachments)) {
|
|
@@ -5704,12 +5853,12 @@ class Agent {
|
|
|
5704
5853
|
writeSessionArchive(messages, mode, model) {
|
|
5705
5854
|
const archiveDir = this.archiveDir();
|
|
5706
5855
|
fs.mkdirSync(archiveDir, { recursive: true });
|
|
5707
|
-
const archive = this.buildSessionArchive(messages, mode, model, archiveDir);
|
|
5856
|
+
const archive = this.buildSessionArchive(messages, { mode, model, goal: this.serializeGoal() }, archiveDir);
|
|
5708
5857
|
fs.writeFileSync(path.join(archiveDir, archive.filename), archive.markdown, 'utf-8');
|
|
5709
5858
|
return archive.filename;
|
|
5710
5859
|
}
|
|
5711
|
-
async writeSessionArchiveAsync(messages,
|
|
5712
|
-
const archive = this.buildSessionArchive(messages,
|
|
5860
|
+
async writeSessionArchiveAsync(messages, context, archiveDir = this.archiveDir()) {
|
|
5861
|
+
const archive = this.buildSessionArchive(messages, context, archiveDir);
|
|
5713
5862
|
await fs.promises.mkdir(archiveDir, { recursive: true });
|
|
5714
5863
|
const outPath = path.join(archiveDir, archive.filename);
|
|
5715
5864
|
const tempPath = `${outPath}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
@@ -5803,25 +5952,23 @@ class Agent {
|
|
|
5803
5952
|
* large markdown payload and manifest use promise-based filesystem I/O so
|
|
5804
5953
|
* independent workspaces can archive in parallel without freezing Electron.
|
|
5805
5954
|
*/
|
|
5806
|
-
async archiveConversationAsync(conversationId) {
|
|
5955
|
+
async archiveConversationAsync(conversationId, ws = this.workspace.current) {
|
|
5807
5956
|
// Archive payloads intentionally start in parallel. The final state
|
|
5808
5957
|
// mutation below operates on the latest locked disk snapshot, so no
|
|
5809
5958
|
// JavaScript queue is needed for independent targets in one workspace.
|
|
5810
|
-
return await this.archiveConversationAsyncUnlocked(conversationId);
|
|
5959
|
+
return await this.archiveConversationAsyncUnlocked(conversationId, ws);
|
|
5811
5960
|
}
|
|
5812
|
-
async archiveConversationAsyncUnlocked(conversationId) {
|
|
5813
|
-
const ws = this.workspace.current;
|
|
5961
|
+
async archiveConversationAsyncUnlocked(conversationId, targetWorkspace = this.workspace.current) {
|
|
5962
|
+
const ws = targetWorkspace || this.workspace.current;
|
|
5814
5963
|
if (!ws)
|
|
5815
5964
|
return null;
|
|
5816
5965
|
const clean = this.safeConversationId(conversationId || 'default');
|
|
5817
|
-
const stateKey = this.
|
|
5966
|
+
const stateKey = this.workspaceConversationStateKeyFor(clean, ws);
|
|
5818
5967
|
if (!stateKey)
|
|
5819
5968
|
return null;
|
|
5820
5969
|
const memoryKey = `${ws.isInternal ? 'internal' : 'external'}:${path.resolve(ws.path)}::conversation:${clean}`;
|
|
5821
5970
|
const archiveDir = path.join(ws.path, 'archive');
|
|
5822
|
-
const workspacePrefix = this.
|
|
5823
|
-
const archiveMode = this.modeName();
|
|
5824
|
-
const archiveModel = this.model;
|
|
5971
|
+
const workspacePrefix = this.workspaceConversationPrefixFor(ws) || '';
|
|
5825
5972
|
// readStoredConversationState returns a cache object. Clone it before any
|
|
5826
5973
|
// asynchronous gap so concurrent archive requests cannot mutate one
|
|
5827
5974
|
// another's source snapshot.
|
|
@@ -5831,13 +5978,23 @@ class Agent {
|
|
|
5831
5978
|
if (persisted)
|
|
5832
5979
|
this.normalizeConversationTree(persisted);
|
|
5833
5980
|
const memory = this.workspaceConversations.get(memoryKey);
|
|
5981
|
+
const archiveMode = persisted?.mode || memory?.mode || 'build';
|
|
5982
|
+
const archiveSelection = persisted?.modelSelection || memory?.modelSelection;
|
|
5983
|
+
const archiveModel = archiveSelection?.kind === 'deployment'
|
|
5984
|
+
? archiveSelection.modelId
|
|
5985
|
+
: archiveSelection?.kind === 'auto' ? 'auto' : 'auto';
|
|
5986
|
+
const archiveGoal = persisted?.goal || memory?.goal || null;
|
|
5834
5987
|
const persistedMessagesAvailable = persisted?.chatMessages !== undefined;
|
|
5835
5988
|
const sourceMessages = persisted?.chatMessages ?? memory?.chatMessages ?? [];
|
|
5836
5989
|
const sourceHistory = persistedMessagesAvailable
|
|
5837
5990
|
? (persisted?.history ?? [])
|
|
5838
5991
|
: (memory?.history ?? persisted?.history ?? []);
|
|
5839
5992
|
const messages = this.normalizeConversationChatMessages(sourceMessages, sourceHistory);
|
|
5840
|
-
const filename = await this.writeSessionArchiveAsync(messages,
|
|
5993
|
+
const filename = await this.writeSessionArchiveAsync(messages, {
|
|
5994
|
+
mode: archiveMode,
|
|
5995
|
+
model: archiveModel,
|
|
5996
|
+
goal: archiveGoal,
|
|
5997
|
+
}, archiveDir);
|
|
5841
5998
|
const archiveEntry = persisted ? JSON.parse(JSON.stringify(persisted)) : {
|
|
5842
5999
|
title: this.titleFromMessages(messages, clean),
|
|
5843
6000
|
chatMessages: messages,
|
|
@@ -5897,7 +6054,9 @@ class Agent {
|
|
|
5897
6054
|
this.workspaceConversations.delete(memoryKey);
|
|
5898
6055
|
const duplicateMemoryKey = `${ws.isInternal ? 'internal' : 'external'}:${path.resolve(ws.path)}::conversation:${clean}`;
|
|
5899
6056
|
this.workspaceConversations.delete(duplicateMemoryKey);
|
|
5900
|
-
|
|
6057
|
+
const currentWs = this.workspace.current;
|
|
6058
|
+
const isCurrentWorkspace = !!currentWs && path.resolve(currentWs.path) === path.resolve(ws.path);
|
|
6059
|
+
if (isCurrentWorkspace && clean === this.safeConversationId(this.activeConversationId || 'default')) {
|
|
5901
6060
|
this.activeConversationId = nextActiveId || 'default';
|
|
5902
6061
|
this.loadWorkspaceConversationState();
|
|
5903
6062
|
}
|
|
@@ -7345,7 +7504,7 @@ class Agent {
|
|
|
7345
7504
|
const settled = await this.waitForSubagentSettlement(accepted.data.id);
|
|
7346
7505
|
return `${accepted.output}\n${settled?.result || settled?.error || ''}`.trim();
|
|
7347
7506
|
}
|
|
7348
|
-
async handleSubagentEnvelope(args) {
|
|
7507
|
+
async handleSubagentEnvelope(args, requireRunningBuild = false) {
|
|
7349
7508
|
try {
|
|
7350
7509
|
const params = JSON.parse(args);
|
|
7351
7510
|
const preset = this.resolveSubagentPreset(params);
|
|
@@ -7368,7 +7527,39 @@ class Agent {
|
|
|
7368
7527
|
&& requestedModel === activeDeployment.modelId
|
|
7369
7528
|
? `deployment:${encodeURIComponent(activeDeployment.providerId)}:${encodeURIComponent(activeDeployment.modelId)}`
|
|
7370
7529
|
: requestedModel;
|
|
7371
|
-
const
|
|
7530
|
+
const buildRunId = this.currentWorkRunId();
|
|
7531
|
+
const runningBuild = buildRunId
|
|
7532
|
+
? this.workRuns.find(run => run.runId === buildRunId && run.status === 'running')
|
|
7533
|
+
: undefined;
|
|
7534
|
+
const limit = this.subagentConcurrencyLimit();
|
|
7535
|
+
if (requireRunningBuild && !runningBuild) {
|
|
7536
|
+
return {
|
|
7537
|
+
ok: false,
|
|
7538
|
+
output: '[SubAgent terminated] No running Build Block owns this call; no SubAgent was created.',
|
|
7539
|
+
error: 'SubAgent tool calls require a running Build Block.',
|
|
7540
|
+
metadata: { kind: 'subagent', buildRunId: buildRunId || '', limit, terminated: true },
|
|
7541
|
+
};
|
|
7542
|
+
}
|
|
7543
|
+
if (buildRunId && !runningBuild) {
|
|
7544
|
+
return {
|
|
7545
|
+
ok: false,
|
|
7546
|
+
output: `[SubAgent terminated] Build Block ${buildRunId} is not running; no SubAgent was created.`,
|
|
7547
|
+
error: 'SubAgent creation requires a running Build Block.',
|
|
7548
|
+
metadata: { kind: 'subagent', buildRunId, limit, terminated: true },
|
|
7549
|
+
};
|
|
7550
|
+
}
|
|
7551
|
+
if (runningBuild) {
|
|
7552
|
+
const activeForBuild = this.subagents.activeCountForBuild(buildRunId);
|
|
7553
|
+
if (activeForBuild >= limit) {
|
|
7554
|
+
return {
|
|
7555
|
+
ok: false,
|
|
7556
|
+
output: `[SubAgent terminated] Build Block ${buildRunId} reached the ${this.intelligence === 'ultra' ? 'Ultra' : 'non-Ultra'} hard limit (${limit}); no SubAgent was created or queued.`,
|
|
7557
|
+
error: `SubAgent hard limit reached for Build Block ${buildRunId}: ${activeForBuild}/${limit}.`,
|
|
7558
|
+
metadata: { kind: 'subagent', buildRunId, intelligence: this.intelligence, activeForBuild, limit, terminated: true },
|
|
7559
|
+
};
|
|
7560
|
+
}
|
|
7561
|
+
}
|
|
7562
|
+
const id = this.subagents.create(name, prompt, peerModel, params.input_mode || params.inputMode || preset?.inputMode || 'guide', peerMode, this.runtimeActorId, peerFlow, peerGoal, Number(params.flow_pc ?? params.flowPc ?? (peerMode === 'flow' ? this.flowPc : 0)), runningBuild?.runId || '', this.intelligence);
|
|
7372
7563
|
const sa = this.subagents.get(id);
|
|
7373
7564
|
if (sa && preset) {
|
|
7374
7565
|
sa.metadata = {
|
|
@@ -8200,6 +8391,17 @@ class Agent {
|
|
|
8200
8391
|
}
|
|
8201
8392
|
latestSubmittedImages(attachmentId = '') {
|
|
8202
8393
|
const normalizedId = String(attachmentId || '').trim();
|
|
8394
|
+
const captured = (0, conversationAttachments_1.hydrateConversationImageAttachments)(this.rootPath, this.latestCapturedImageInputs).flatMap(attachment => attachment.dataUrl
|
|
8395
|
+
? [{ id: attachment.id, dataUrl: attachment.dataUrl }]
|
|
8396
|
+
: []);
|
|
8397
|
+
if (normalizedId) {
|
|
8398
|
+
const capturedMatch = captured.find(item => item.id === normalizedId);
|
|
8399
|
+
if (capturedMatch)
|
|
8400
|
+
return [capturedMatch];
|
|
8401
|
+
}
|
|
8402
|
+
else if (captured.length) {
|
|
8403
|
+
return captured;
|
|
8404
|
+
}
|
|
8203
8405
|
for (let index = this.chatMessages.length - 1; index >= 0; index -= 1) {
|
|
8204
8406
|
const message = this.chatMessages[index];
|
|
8205
8407
|
if (message?.role !== 'user')
|
|
@@ -8830,7 +9032,7 @@ class Agent {
|
|
|
8830
9032
|
if (this.intelligence === 'ultra') {
|
|
8831
9033
|
parts.push([
|
|
8832
9034
|
'[Ultra Intelligence – Orchestrator Role]',
|
|
8833
|
-
'You are the lead orchestrator. Actively decompose complex tasks into parallel sub-tasks. Use the `
|
|
9035
|
+
'You are the lead orchestrator. Actively decompose complex tasks into parallel sub-tasks. Use the `SubAgent` tool to create specialized SubAgents for each distinct sub-task. Use `task_create` only for the conversation checklist; it never creates a SubAgent. Coordinate the SubAgent team: assign clear responsibilities, merge results, resolve conflicts, and produce a unified final output. SubAgents are your team; delegate aggressively and manage them as a manager, not just a tool caller.',
|
|
8834
9036
|
'Do not attempt to do all the work yourself. Use SubAgents for parallel investigation, verification, implementation, and review.',
|
|
8835
9037
|
].join('\n'));
|
|
8836
9038
|
}
|
|
@@ -8937,7 +9139,7 @@ class Agent {
|
|
|
8937
9139
|
'- Build history disclosure is two-layered. The request prompt contains only each historical Build Block user input, final summary, and completion status. When the current task continues, fixes, verifies, or depends on earlier Build Blocks, proactively call build_history_query to read the concrete tool activity and results of the relevant block, and reuse that information instead of re-investigating (re-running commands or re-reading files) from scratch. Querying history is read-only and never authorizes resuming that work; do not query merely to answer completion status already shown in the prompt.',
|
|
8938
9140
|
'- Linked plan disclosure: a durable conversation-linked Markdown plan exists and can be inspected or updated with linked_plan when explicitly needed or required by Plan mode. Its full Markdown and revision are not injected into every model request.',
|
|
8939
9141
|
'- A memory_lab_update, memory_lab_delete, or memory_lab_reindex call is unfinished until its awaited tool result contains rebuildReceipt.completed=true. The completion receipt is represented by the tool activity inside the current Build block and should not be repeated as a separate completion message.',
|
|
8940
|
-
`- Skills and subagents: skill searches enabled metadata and loads one SKILL.md body on demand; skill_download installs offline skill folders;
|
|
9142
|
+
`- Skills and subagents: skill searches enabled metadata and loads one SKILL.md body on demand; skill_download installs offline skill folders; SubAgent creates constrained peer agents tracked in agent state. task_create is only for the conversation checklist and never creates a SubAgent.`,
|
|
8941
9143
|
`- Visible output contract: assistant replies are sanitized before display to remove hidden-reasoning markers. ${visibleOutputContract}`,
|
|
8942
9144
|
'- During Build work, before the first tool call and between materially different tool phases, emit a concise public progress explanation of what you are checking or changing and why. This is visible commentary, not hidden chain-of-thought. Do not wait until the final answer to explain the work.',
|
|
8943
9145
|
].join('\n');
|
|
@@ -158,6 +158,9 @@ export declare const agentKernelRunnerInternals: {
|
|
|
158
158
|
TOOL_PROVISION_NAME: string;
|
|
159
159
|
INITIAL_TOOL_SCHEMA_LIMIT: number;
|
|
160
160
|
SUBAGENT_CORE_TOOL_NAMES: Set<string>;
|
|
161
|
+
TASK_CHECKLIST_CORE_TOOL_NAMES: Set<string>;
|
|
162
|
+
BASIC_INITIAL_TOOL_NAMES: Set<string>;
|
|
163
|
+
ALWAYS_AVAILABLE_AGENT_TOOL_NAMES: Set<string>;
|
|
161
164
|
};
|
|
162
165
|
declare function imageMimeForPath(imagePath: string): string;
|
|
163
166
|
export {};
|