newmark-agent 0.3.12 → 0.4.2
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/dist/cli-commands.d.ts +1 -0
- package/dist/cli-commands.js +11 -2
- package/dist/context/domain/types.d.ts +37 -0
- package/dist/context/services/context-orchestrator.js +2 -0
- package/dist/conversation-utility-host.bundle.cjs +1259 -132
- package/dist/conversation-utility-host.js +3 -0
- package/dist/core/agent.d.ts +139 -5
- package/dist/core/agent.js +964 -82
- package/dist/core/agentKernel/agent-loop.js +29 -3
- package/dist/core/agentKernel/types.d.ts +7 -0
- package/dist/core/agentKernelRunner.d.ts +2 -0
- package/dist/core/agentKernelRunner.js +121 -19
- package/dist/core/conversationKernel.d.ts +5 -0
- package/dist/core/conversationKernel.js +29 -0
- package/dist/core/dshCompatibility.d.ts +198 -0
- package/dist/core/dshCompatibility.js +600 -0
- package/dist/core/electronUtilityAgentClient.d.ts +4 -0
- package/dist/core/electronUtilityAgentClient.js +4 -0
- package/dist/core/electronUtilityRuntimePool.d.ts +8 -0
- package/dist/core/electronUtilityRuntimePool.js +14 -0
- package/dist/core/mcpManager.d.ts +1 -0
- package/dist/core/mcpManager.js +100 -10
- package/dist/core/subagent.d.ts +6 -0
- package/dist/core/subagent.js +22 -1
- package/dist/core/toolPolicy.d.ts +15 -0
- package/dist/core/toolPolicy.js +174 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/utilityAgentProtocol.d.ts +8 -1
- package/dist/core/workspace.d.ts +9 -0
- package/dist/core/workspace.js +48 -1
- package/dist/core/wslAgentClient.d.ts +4 -0
- package/dist/core/wslAgentClient.js +4 -0
- package/dist/core/wslAgentProtocol.d.ts +8 -1
- package/dist/core/wslAgentRuntimePool.d.ts +8 -0
- package/dist/core/wslAgentRuntimePool.js +15 -0
- package/dist/launcher.js +8 -0
- package/dist/llm/provider.d.ts +1 -1
- package/dist/llm/provider.js +4 -3
- package/dist/main.js +163 -11
- package/dist/preload.js +11 -0
- package/dist/providers/chat-completions.adapter.js +41 -15
- package/dist/providers/provider-adapter.d.ts +3 -0
- package/dist/toolchain/registry/tool-registry.d.ts +13 -1
- package/dist/toolchain/registry/tool-registry.js +8 -0
- package/dist/toolchain/registry-seeder.js +52 -6
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +39 -2
- package/dist/tools/nativeTools.js +6 -1
- package/dist/tui/src/app.js +24 -0
- package/dist/tui/src/i18n.js +151 -0
- package/dist/tui/src/render.js +152 -61
- package/dist/tui/src/state.js +83 -0
- package/dist/ui/index.html +2669 -234
- package/dist/ui/lucide-sprite.svg +31 -0
- package/dist/wsl-agent-host.bundle.cjs +1259 -132
- package/dist/wsl-agent-host.js +3 -0
- package/package.json +6 -10
- package/Flow/Electron-Debug-Release.Flow.json +0 -43
- package/Flow/Flow.md +0 -9
- package/Flow/UI-Feature-Integration.Flow.json +0 -96
|
@@ -193,9 +193,35 @@ async function executeToolCalls(toolCalls, context, config, signal) {
|
|
|
193
193
|
}
|
|
194
194
|
};
|
|
195
195
|
if (config.toolExecution === 'parallel') {
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
|
|
196
|
+
// DSH 式并发安全分级:只有 concurrencySafe 工具才能与兄弟调用重叠执行,
|
|
197
|
+
// 有副作用的工具(缺省独占)形成串行屏障,避免盲目 Promise.all 导致
|
|
198
|
+
// write/edit/bash/browser_* 等副作用工具竞态。连续的并发安全调用聚合为
|
|
199
|
+
// 一个 Promise.all 批次;独占调用等待前面批次全部 settle 后单独执行。
|
|
200
|
+
const results = [];
|
|
201
|
+
let index = 0;
|
|
202
|
+
while (index < toolCalls.length) {
|
|
203
|
+
const call = toolCalls[index];
|
|
204
|
+
const tool = tools.find(candidate => candidate.name === call.name);
|
|
205
|
+
if (tool && tool.concurrencySafe === true) {
|
|
206
|
+
// 聚合连续的并发安全调用为一个并行批次。
|
|
207
|
+
const batch = [];
|
|
208
|
+
while (index < toolCalls.length) {
|
|
209
|
+
const candidate = toolCalls[index];
|
|
210
|
+
const candidateTool = tools.find(t => t.name === candidate.name);
|
|
211
|
+
if (!candidateTool || candidateTool.concurrencySafe !== true)
|
|
212
|
+
break;
|
|
213
|
+
batch.push(candidate);
|
|
214
|
+
index += 1;
|
|
215
|
+
}
|
|
216
|
+
results.push(...(await Promise.all(batch.map(c => executeOne(c)))));
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
// 独占工具:串行屏障,等待前面批次全部 settle 后单独执行。
|
|
220
|
+
results.push(await executeOne(call));
|
|
221
|
+
index += 1;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return results;
|
|
199
225
|
}
|
|
200
226
|
const results = [];
|
|
201
227
|
for (const call of toolCalls)
|
|
@@ -10,6 +10,13 @@ export type AgentTool = Tool & {
|
|
|
10
10
|
terminate?: boolean;
|
|
11
11
|
}>;
|
|
12
12
|
executionMode?: 'sequential' | 'parallel';
|
|
13
|
+
/**
|
|
14
|
+
* 是否可与兄弟 tool call 并发执行(DSH isConcurrencySafe 语义的静态落地)。
|
|
15
|
+
* 缺省为 false(独占):有副作用的工具(write/edit/bash/browser_* 等)必须串行,
|
|
16
|
+
* 只有只读工具(read/glob/grep/web_search/pwd 等)显式声明 true 才允许并行。
|
|
17
|
+
* 这是 Newmark 从 DSH 学习的并发安全分级,避免盲目 Promise.all 导致副作用工具竞态。
|
|
18
|
+
*/
|
|
19
|
+
concurrencySafe?: boolean;
|
|
13
20
|
};
|
|
14
21
|
export type QueueMode = 'all' | 'one-at-a-time';
|
|
15
22
|
export interface ContextTransformResult {
|
|
@@ -75,6 +75,8 @@ interface KernelTool {
|
|
|
75
75
|
terminate?: boolean;
|
|
76
76
|
}>;
|
|
77
77
|
executionMode?: 'sequential' | 'parallel';
|
|
78
|
+
/** 并发安全分级(DSH isConcurrencySafe):只读工具 true,有副作用工具缺省串行。 */
|
|
79
|
+
concurrencySafe?: boolean;
|
|
78
80
|
}
|
|
79
81
|
declare function normalizePublicProviderError(error: unknown, secrets?: unknown[]): string;
|
|
80
82
|
export declare function runAgentKernel(agent: Agent): Promise<StreamToken[]>;
|
|
@@ -493,6 +493,8 @@ async function runAgentKernel(agent) {
|
|
|
493
493
|
stream.push({ type: 'start', partial });
|
|
494
494
|
let text = '';
|
|
495
495
|
let thinking = '';
|
|
496
|
+
let thinkingStarted = false;
|
|
497
|
+
let thinkingRecorded = false;
|
|
496
498
|
let contentIndex = 0;
|
|
497
499
|
const finalContent = [];
|
|
498
500
|
let textStarted = false;
|
|
@@ -514,14 +516,20 @@ async function runAgentKernel(agent) {
|
|
|
514
516
|
const currentCompressionAt = currentAgent.lastCompression?.at || '';
|
|
515
517
|
const compressionCompleted = !!currentCompressionAt && currentCompressionAt !== bootstrappedCompressionAt;
|
|
516
518
|
const includeBootstrap = providerRequestCount === 0 || compressionCompleted;
|
|
519
|
+
// Keep the stable base prompt identical across tool sub-turns. The
|
|
520
|
+
// request-scoped ledger/bootstrap is needed on the first request
|
|
521
|
+
// (and once after compression), but re-injecting it on every round
|
|
522
|
+
// makes otherwise cacheable prompt prefixes look like new prompts.
|
|
517
523
|
const requestSystemPrompt = [
|
|
518
524
|
context.systemPrompt || '',
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
+
includeBootstrap || compressionCompleted
|
|
526
|
+
? buildRequestTaskFocus(currentAgent, context.messages, {
|
|
527
|
+
includeBootstrap,
|
|
528
|
+
compressionCompleted,
|
|
529
|
+
activeTools: context.tools || [],
|
|
530
|
+
toolCatalog: currentAgent.cachedToolDefinitions(),
|
|
531
|
+
})
|
|
532
|
+
: '',
|
|
525
533
|
].filter(Boolean).join('\n\n');
|
|
526
534
|
providerRequestCount += 1;
|
|
527
535
|
if (compressionCompleted)
|
|
@@ -532,7 +540,9 @@ async function runAgentKernel(agent) {
|
|
|
532
540
|
messages: newmarkMessages,
|
|
533
541
|
tools: context.tools || [],
|
|
534
542
|
});
|
|
535
|
-
for await (const token of currentProvider.chatStreamWithTools(currentModelName, newmarkMessages, requestSystemPrompt, temperature, maxTokens, toProviderToolDefinitions(context.tools || []), options?.signal, reasoningEffort)
|
|
543
|
+
for await (const token of currentProvider.chatStreamWithTools(currentModelName, newmarkMessages, requestSystemPrompt, temperature, maxTokens, toProviderToolDefinitions(context.tools || []), options?.signal, reasoningEffort, currentAgent.config.getBool('context', 'provider_session_id')
|
|
544
|
+
? currentAgent.activeConversationId
|
|
545
|
+
: undefined)) {
|
|
536
546
|
if (!firstTokenRecorded && ((token.type === 'text' && token.text) || (token.type === 'tool_call' && token.toolCall))) {
|
|
537
547
|
firstTokenRecorded = true;
|
|
538
548
|
(0, performanceDiagnostics_1.emitPerformanceEvent)({ stage: 'first_token', durationMs: Date.now() - requestStartedAt, conversationId: currentAgent.activeConversationId });
|
|
@@ -554,10 +564,20 @@ async function runAgentKernel(agent) {
|
|
|
554
564
|
if (token.reasoningContent) {
|
|
555
565
|
const delta = token.reasoningContent.slice(thinking.length);
|
|
556
566
|
thinking = token.reasoningContent;
|
|
567
|
+
if (!thinkingStarted) {
|
|
568
|
+
thinkingStarted = true;
|
|
569
|
+
// 记录“思考中”的公开活动标记;推理文本绝不进入该事件。
|
|
570
|
+
currentAgent.emitWorkEvent({ type: 'thought', content: '' });
|
|
571
|
+
}
|
|
557
572
|
if (delta) {
|
|
558
573
|
stream.push({ type: 'thinking_delta', contentIndex, delta, partial: assistantMessage(model, thinking ? [{ type: 'text', text }] : [], 'stop') });
|
|
559
574
|
}
|
|
560
575
|
}
|
|
576
|
+
if (thinkingStarted && !thinkingRecorded && ((token.type === 'text' && token.text) || (token.type === 'tool_call' && token.toolCall))) {
|
|
577
|
+
thinkingRecorded = true;
|
|
578
|
+
// 思考结束:持久化完整思考过程,供 Build Block 展开查看(仍不进入聊天正文)。
|
|
579
|
+
currentAgent.emitWorkEvent({ type: 'thought_result', content: thinking });
|
|
580
|
+
}
|
|
561
581
|
if (token.type === 'text' && token.text) {
|
|
562
582
|
if (currentAgent.isLlmErrorText(token.text)) {
|
|
563
583
|
text += token.text;
|
|
@@ -601,6 +621,10 @@ async function runAgentKernel(agent) {
|
|
|
601
621
|
}
|
|
602
622
|
if (process.env.NEWMARK_PROVIDER_DIAGNOSTICS === '1')
|
|
603
623
|
console.error('[NewmarkKernel] provider-loop-complete');
|
|
624
|
+
if (thinkingStarted && !thinkingRecorded) {
|
|
625
|
+
thinkingRecorded = true;
|
|
626
|
+
currentAgent.emitWorkEvent({ type: 'thought_result', content: thinking });
|
|
627
|
+
}
|
|
604
628
|
if (options?.signal?.aborted) {
|
|
605
629
|
const aborted = assistantMessage(model, text ? [{ type: 'text', text }] : [], 'aborted');
|
|
606
630
|
stream.push({ type: 'done', reason: 'aborted', message: aborted });
|
|
@@ -729,21 +753,26 @@ function buildBuildContextBootstrap(agent, messages, options) {
|
|
|
729
753
|
.filter(definition => toolDefinitionName(definition) !== TOOL_PROVISION_NAME)
|
|
730
754
|
.map(definition => `- ${toolDefinitionName(definition)}: ${compactToolDescription(toolDefinitionDescription(definition))}`);
|
|
731
755
|
const retainedMessages = messages.length;
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
756
|
+
// 缓存命中关键:压缩后不再把压缩摘要冗余注入 bootstrap——压缩摘要已通过
|
|
757
|
+
// transformContext 的 compressionContinuationPrompt 写入 messages 前缀。这里
|
|
758
|
+
// 保持 bootstrap 文案在「压缩前/后」字节稳定,避免 compressionCompleted 分支
|
|
759
|
+
// 单独改变 system 内容而让 provider 前缀缓存失效。
|
|
760
|
+
// 首 Build 命名:仅当前对话标题仍自动生成时注入一次,缓存友好(后续 Build 不含)。
|
|
761
|
+
const renameDirective = agent.shouldPromptConversationRename()
|
|
762
|
+
? [
|
|
763
|
+
'## Conversation Naming Bootstrap',
|
|
764
|
+
'This is the FIRST Build Block of a NEW conversation whose title is still auto-generated. Call conversation_rename ONCE now with a short, concrete noun-phrase title describing this task (a few words, no sentences, no quoted prompts). This is a one-time, cache-friendly step so the conversation list shows a meaningful name.',
|
|
765
|
+
]
|
|
766
|
+
: [];
|
|
735
767
|
return [
|
|
736
768
|
'## Build Context Bootstrap',
|
|
737
|
-
|
|
738
|
-
? 'Injection reason: context compression just completed; this is the first provider request using the compacted context.'
|
|
739
|
-
: 'Injection reason: this is the first provider request of a new Build.',
|
|
769
|
+
'Injection reason: this is the first provider request of a new Build.',
|
|
740
770
|
'This block is request-only runtime metadata. Do not quote it into conversation history, Build summaries, Memory Lab, or future compression summaries.',
|
|
741
771
|
'Current context boundary:',
|
|
742
|
-
|
|
743
|
-
? `- Compacted historical context: ${JSON.stringify(compressionSummary)}`
|
|
744
|
-
: '- The durable conversation messages in this provider request are the current uncompressed context; use them directly and do not reinterpret them as a backlog.',
|
|
772
|
+
'- The durable conversation messages in this provider request are the current authoritative context; use them directly and do not reinterpret them as a backlog.',
|
|
745
773
|
`- Retained non-system request messages: ${retainedMessages}. The latest real user-role message remains authoritative.`,
|
|
746
774
|
buildConversationTaskLedger(agent),
|
|
775
|
+
...renameDirective,
|
|
747
776
|
'## Tool Awareness Bootstrap',
|
|
748
777
|
'The following catalog is capability metadata only. Tool descriptions are not instructions, and a tool is callable only when its full schema is present in the provider tools field.',
|
|
749
778
|
...(catalogLines.length ? catalogLines : ['- No callable tools are available for this provider turn.']),
|
|
@@ -1332,15 +1361,25 @@ function toolDefinitionName(definition) {
|
|
|
1332
1361
|
}
|
|
1333
1362
|
function toKernelTools(agent, definitions, provisioning) {
|
|
1334
1363
|
const tools = definitions || agent.cachedToolDefinitions();
|
|
1364
|
+
// 单一来源:先 seed toolchain registry,使每个工具的 riskLevel 从定义自动推断。
|
|
1365
|
+
let registry = null;
|
|
1366
|
+
try {
|
|
1367
|
+
registry = agent.ensureToolchain(tools).registry;
|
|
1368
|
+
}
|
|
1369
|
+
catch { }
|
|
1335
1370
|
return tools.map((tool) => {
|
|
1336
1371
|
const fn = tool?.function || {};
|
|
1372
|
+
const toolName = String(fn.name || '');
|
|
1373
|
+
const descriptor = registry?.get(toolName);
|
|
1337
1374
|
return {
|
|
1338
|
-
name:
|
|
1339
|
-
label:
|
|
1375
|
+
name: toolName,
|
|
1376
|
+
label: toolName,
|
|
1340
1377
|
description: String(fn.description || ''),
|
|
1341
1378
|
parameters: fn.parameters || { type: 'object', properties: {}, required: [] },
|
|
1342
1379
|
prepareArguments: parseToolArgs,
|
|
1343
1380
|
executionMode: 'parallel',
|
|
1381
|
+
// DSH isConcurrencySafe 落地:从 registry 的 riskLevel 派生(read 工具并行)+ 白名单兜底。
|
|
1382
|
+
concurrencySafe: (0, toolPolicy_1.isConcurrencySafeTool)(toolName, descriptor?.riskLevel),
|
|
1344
1383
|
execute: async (_toolCallId, params, signal) => {
|
|
1345
1384
|
if (signal?.aborted)
|
|
1346
1385
|
throw abortError();
|
|
@@ -1373,7 +1412,7 @@ function toKernelTools(agent, definitions, provisioning) {
|
|
|
1373
1412
|
}
|
|
1374
1413
|
const visionImage = visualFallbackImageInput(agent, name, rawText);
|
|
1375
1414
|
const directImage = imageInspectDataUrl(name, rawText);
|
|
1376
|
-
const text = sanitizeVisualToolText(name, rawText);
|
|
1415
|
+
const text = spillOversizedToolResult(agent, name, sanitizeVisualToolText(name, rawText));
|
|
1377
1416
|
const content = [{ type: 'text', text }];
|
|
1378
1417
|
if (visionImage.imagePath)
|
|
1379
1418
|
content.push({ type: 'image', imagePath: visionImage.imagePath, mimeType: imageMimeForPath(visionImage.imagePath) });
|
|
@@ -1414,6 +1453,51 @@ function toolResultIndicatesFailure(text) {
|
|
|
1414
1453
|
return false;
|
|
1415
1454
|
}
|
|
1416
1455
|
}
|
|
1456
|
+
/** 内联回传 model 的单个工具结果字符上限(约 6000 token)。
|
|
1457
|
+
* 超过则裁剪为「头部结论 + 尾部证据」,避免巨型 read/grep/bash 输出整段
|
|
1458
|
+
* 内联进 context 撑爆窗口(DSH tool-result-pruner 的内联落地)。 */
|
|
1459
|
+
const INLINE_TOOL_RESULT_MAX_CHARS = 24000;
|
|
1460
|
+
/** 有界处理内联工具结果。只对会产出大文本的工具生效;带视觉/结构化 JSON
|
|
1461
|
+
* 的工具结果保持原样(截断/落盘会破坏 JSON 结构)。 */
|
|
1462
|
+
function boundInlineToolResult(name, text) {
|
|
1463
|
+
const value = String(text || '');
|
|
1464
|
+
if (value.length <= INLINE_TOOL_RESULT_MAX_CHARS)
|
|
1465
|
+
return value;
|
|
1466
|
+
// 结构化结果(JSON/视觉/浏览器/子代理/计划等)不可安全截断,保持原样。
|
|
1467
|
+
if (['computer_use', 'browser_use', 'pdf_read', 'image_inspect', 'image_display', 'task', 'subagent_send', 'subagent_result', 'subagent_read', 'linked_plan', 'question'].includes(name)) {
|
|
1468
|
+
return value;
|
|
1469
|
+
}
|
|
1470
|
+
const headChars = Math.floor(INLINE_TOOL_RESULT_MAX_CHARS * 0.6);
|
|
1471
|
+
const tailChars = Math.max(0, INLINE_TOOL_RESULT_MAX_CHARS - headChars - 48);
|
|
1472
|
+
const head = value.slice(0, headChars).trimEnd();
|
|
1473
|
+
const tail = value.slice(-tailChars).trimStart();
|
|
1474
|
+
return `${head}\n\n[...tool result truncated: ${value.length - headChars - tailChars} chars omitted from middle...]\n\n${tail}`;
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* 超大工具结果的完整处理:落盘完整内容(不进上下文),上下文只保留一个
|
|
1478
|
+
* tiny 引用标记 + 头部预览。Agent 之后可调用 compress_tool_result(artifact_id)
|
|
1479
|
+
* 把完整内容恢复为格式保留的压缩摘要;不调用则上下文中仅剩该引用(等价于
|
|
1480
|
+
* 截断,但完整内容在盘上可恢复,不丢失)。
|
|
1481
|
+
*/
|
|
1482
|
+
function spillOversizedToolResult(agent, name, text) {
|
|
1483
|
+
const value = String(text || '');
|
|
1484
|
+
if (value.length <= INLINE_TOOL_RESULT_MAX_CHARS)
|
|
1485
|
+
return value;
|
|
1486
|
+
// 结构化结果不可安全落盘引用(破坏 JSON 结构),保持原样。
|
|
1487
|
+
if (['computer_use', 'browser_use', 'pdf_read', 'image_inspect', 'image_display', 'task', 'subagent_send', 'subagent_result', 'subagent_read', 'linked_plan', 'question'].includes(name)) {
|
|
1488
|
+
return value;
|
|
1489
|
+
}
|
|
1490
|
+
const artifactId = agent.storeToolResultArtifact(name, value);
|
|
1491
|
+
const headPreview = value.slice(0, 800).trimEnd();
|
|
1492
|
+
return [
|
|
1493
|
+
`[oversized_tool_result tool="${name}" artifact_id="${artifactId}" chars="${value.length}"]`,
|
|
1494
|
+
'The full result was written out of context. The preview below is truncated to 800 chars.',
|
|
1495
|
+
'Call compress_tool_result with this artifact_id to recover the full result as a format-preserving summary, or leave it truncated.',
|
|
1496
|
+
'',
|
|
1497
|
+
headPreview,
|
|
1498
|
+
'...(preview truncated)',
|
|
1499
|
+
].join('\n');
|
|
1500
|
+
}
|
|
1417
1501
|
function sanitizeVisualToolText(name, text) {
|
|
1418
1502
|
if (name !== 'computer_use' && name !== 'browser_use' && name !== 'pdf_read' && name !== 'image_inspect')
|
|
1419
1503
|
return text;
|
|
@@ -1528,6 +1612,14 @@ async function executeNewmarkTool(agent, name, args, inputSchema, signal) {
|
|
|
1528
1612
|
return agent.handleSubagentResultEnvelope(args).output;
|
|
1529
1613
|
if (name === 'subagent_close')
|
|
1530
1614
|
return agent.handleSubagentCloseEnvelope(args).output;
|
|
1615
|
+
if (name === 'branch_list')
|
|
1616
|
+
return agent.handleBranchList(args).output;
|
|
1617
|
+
if (name === 'branch_send')
|
|
1618
|
+
return agent.handleBranchSend(args).output;
|
|
1619
|
+
if (name === 'branch_read')
|
|
1620
|
+
return agent.handleBranchRead(args).output;
|
|
1621
|
+
if (name === 'branch_create')
|
|
1622
|
+
return agent.handleBranchCreate(args).output;
|
|
1531
1623
|
if (name === 'linked_plan')
|
|
1532
1624
|
return agent.handleLinkedPlanTool(args);
|
|
1533
1625
|
if (name === 'build_history_query')
|
|
@@ -1536,6 +1628,16 @@ async function executeNewmarkTool(agent, name, args, inputSchema, signal) {
|
|
|
1536
1628
|
return (await agent.handleContextCompress(args, signal)).output;
|
|
1537
1629
|
if (name === 'context_history_manage')
|
|
1538
1630
|
return agent.handleContextHistoryManage(args).output;
|
|
1631
|
+
if (name === 'compress_tool_result')
|
|
1632
|
+
return (await agent.handleCompressToolResult(args, signal)).output;
|
|
1633
|
+
if (name === 'background_tool')
|
|
1634
|
+
return (await agent.handleBackgroundTool(args, signal)).output;
|
|
1635
|
+
if (name === 'read_tool_result')
|
|
1636
|
+
return agent.handleReadToolResult(args).output;
|
|
1637
|
+
if (name === 'goal_manage')
|
|
1638
|
+
return agent.handleGoalManage(args).output;
|
|
1639
|
+
if (name === 'conversation_rename')
|
|
1640
|
+
return agent.handleConversationRename(args).output;
|
|
1539
1641
|
if (name === 'question') {
|
|
1540
1642
|
if (agent.config.getStr('agent', 'option_feedback') === 'fully_autonomous')
|
|
1541
1643
|
return '[question] Disabled by fully_autonomous option feedback.';
|
|
@@ -44,6 +44,10 @@ export interface ConversationKernelRunOptions {
|
|
|
44
44
|
inputMode: 'guide' | 'next';
|
|
45
45
|
engine: string;
|
|
46
46
|
}
|
|
47
|
+
export interface ConversationContextCompressOptions {
|
|
48
|
+
keepRecent?: number;
|
|
49
|
+
force?: boolean;
|
|
50
|
+
}
|
|
47
51
|
export interface ConversationKernelRunResult {
|
|
48
52
|
tokens: Array<{
|
|
49
53
|
type: string;
|
|
@@ -194,6 +198,7 @@ export declare class ConversationKernel {
|
|
|
194
198
|
checkpointed: boolean;
|
|
195
199
|
at: string;
|
|
196
200
|
};
|
|
201
|
+
compressContext(target: ConversationTargetInput, options?: ConversationContextCompressOptions): Promise<Record<string, unknown>>;
|
|
197
202
|
rateAutoRoute(target: ConversationTargetInput, score: number, expectedRouteId?: string): AutoRouteRatingResult;
|
|
198
203
|
setWorkRunExpanded(target: ConversationTargetInput, runId: string, expanded: boolean): boolean;
|
|
199
204
|
setInputMode(target: ConversationTargetInput, mode: string): 'guide' | 'next';
|
|
@@ -304,6 +304,35 @@ class ConversationKernel {
|
|
|
304
304
|
at: new Date().toISOString(),
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
|
+
async compressContext(target, options = {}) {
|
|
308
|
+
const normalized = this.normalizeTarget(target);
|
|
309
|
+
const runtime = this.findRuntime(normalized);
|
|
310
|
+
if (runtime?.activePromise) {
|
|
311
|
+
return { ok: false, error: 'Context compression is unavailable while this conversation is running.' };
|
|
312
|
+
}
|
|
313
|
+
const runner = runtime?.runner || this.createRunner(normalized);
|
|
314
|
+
const result = await runner.handleContextCompress(JSON.stringify({
|
|
315
|
+
keep_recent: options.keepRecent,
|
|
316
|
+
force: options.force !== false,
|
|
317
|
+
}));
|
|
318
|
+
let payload = {};
|
|
319
|
+
try {
|
|
320
|
+
const parsed = JSON.parse(result.output || '{}');
|
|
321
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
322
|
+
payload = parsed;
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
payload = { output: result.output };
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
...payload,
|
|
329
|
+
ok: result.ok && payload.ok !== false,
|
|
330
|
+
error: result.error,
|
|
331
|
+
contextWindow: runner.contextWindow(),
|
|
332
|
+
contextCompression: runner.lastCompression,
|
|
333
|
+
displayHistory: { untouched: true, messageCount: runner.chatMessages.length },
|
|
334
|
+
};
|
|
335
|
+
}
|
|
307
336
|
rateAutoRoute(target, score, expectedRouteId = '') {
|
|
308
337
|
const runtime = this.findRuntime(target);
|
|
309
338
|
if (!runtime)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
export interface DshCompatibilityOptions {
|
|
2
|
+
env?: NodeJS.ProcessEnv;
|
|
3
|
+
homeDir?: string;
|
|
4
|
+
pathValue?: string;
|
|
5
|
+
platform?: NodeJS.Platform;
|
|
6
|
+
}
|
|
7
|
+
export interface DshMcpTemplate {
|
|
8
|
+
name: string;
|
|
9
|
+
enabled: false;
|
|
10
|
+
transport: 'stdio' | 'http';
|
|
11
|
+
command?: string;
|
|
12
|
+
args?: string[];
|
|
13
|
+
cwd?: string;
|
|
14
|
+
url?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface DshMcpCandidate {
|
|
17
|
+
name: string;
|
|
18
|
+
source: string;
|
|
19
|
+
importable: boolean;
|
|
20
|
+
reason?: string;
|
|
21
|
+
envKeys: string[];
|
|
22
|
+
headerKeys: string[];
|
|
23
|
+
template?: DshMcpTemplate;
|
|
24
|
+
}
|
|
25
|
+
export interface DshConfigLayer {
|
|
26
|
+
kind: 'bundle' | 'profile' | 'home';
|
|
27
|
+
name: string;
|
|
28
|
+
path: string;
|
|
29
|
+
order: number;
|
|
30
|
+
}
|
|
31
|
+
export interface DshBundleSnapshot {
|
|
32
|
+
name: string;
|
|
33
|
+
version?: string;
|
|
34
|
+
source: string;
|
|
35
|
+
manifestPath: string;
|
|
36
|
+
patch?: string;
|
|
37
|
+
patchPath?: string;
|
|
38
|
+
patchExists: boolean;
|
|
39
|
+
unknownKeys: string[];
|
|
40
|
+
resolved: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface DshProfileSnapshot {
|
|
43
|
+
name: string;
|
|
44
|
+
source: string;
|
|
45
|
+
manifestPath: string;
|
|
46
|
+
bundles: string[];
|
|
47
|
+
unsupportedBundleEntries: number;
|
|
48
|
+
configFiles: string[];
|
|
49
|
+
layers: DshConfigLayer[];
|
|
50
|
+
unknownKeys: string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* DSH dsh-compaction-basic 运行时 seam 到 Newmark 压缩系统的语义映射(纯元数据)。
|
|
54
|
+
* Newmark 落地为运行时等价物,而非复制 DSH 代码;DSH 发现层永不 import/execute 插件主模块。
|
|
55
|
+
*/
|
|
56
|
+
export interface DshCompactionRuntimeSemantics {
|
|
57
|
+
plugin: '@deepseek-ai/dsh-compaction-basic';
|
|
58
|
+
execution: 'native-equivalent';
|
|
59
|
+
seams: {
|
|
60
|
+
apply: {
|
|
61
|
+
dsh: string;
|
|
62
|
+
newmark: string;
|
|
63
|
+
description: string;
|
|
64
|
+
};
|
|
65
|
+
summarize: {
|
|
66
|
+
dsh: string;
|
|
67
|
+
newmark: string;
|
|
68
|
+
description: string;
|
|
69
|
+
};
|
|
70
|
+
compactIfNeeded: {
|
|
71
|
+
dsh: string;
|
|
72
|
+
newmark: string;
|
|
73
|
+
description: string;
|
|
74
|
+
};
|
|
75
|
+
compactNow: {
|
|
76
|
+
dsh: string;
|
|
77
|
+
newmark: string;
|
|
78
|
+
description: string;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
budget: {
|
|
82
|
+
buildBlockTriggerRatio: 0.70;
|
|
83
|
+
longHistoryTriggerRatio: 0.20;
|
|
84
|
+
buildRetainRatio: 0.16;
|
|
85
|
+
longHistoryRetainRatio: 0.05;
|
|
86
|
+
newmarkSource: string;
|
|
87
|
+
};
|
|
88
|
+
cacheReuse: {
|
|
89
|
+
dshStrategy: string;
|
|
90
|
+
newmarkEquivalent: string;
|
|
91
|
+
note: string;
|
|
92
|
+
};
|
|
93
|
+
/** DSH toolResultPruner 的 Newmark 落地(压缩前裁剪大工具结果)。 */
|
|
94
|
+
toolPruning: {
|
|
95
|
+
dsh: string;
|
|
96
|
+
newmark: string;
|
|
97
|
+
thresholdChars: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* DSH 工具层运行时语义映射(纯元数据,永不执行 DSH 插件代码)。
|
|
102
|
+
* 覆盖 DSH 的 ToolRuntime / defineTool / 工具呈现与并发分级语义,映射到
|
|
103
|
+
* Newmark 原生工具执行层。DSH 是 developer preview,schema 可能不兼容变更,
|
|
104
|
+
* 映射层 fail-soft:未识别字段保留为元数据、降级 opaque,不抛错不改写外部文件。
|
|
105
|
+
*/
|
|
106
|
+
export interface DshToolLayerRuntimeSemantics {
|
|
107
|
+
plugin: '@deepseek-ai/dsh-tools';
|
|
108
|
+
execution: 'native-equivalent';
|
|
109
|
+
seams: {
|
|
110
|
+
register: {
|
|
111
|
+
dsh: string;
|
|
112
|
+
newmark: string;
|
|
113
|
+
description: string;
|
|
114
|
+
};
|
|
115
|
+
concurrency: {
|
|
116
|
+
dsh: string;
|
|
117
|
+
newmark: string;
|
|
118
|
+
description: string;
|
|
119
|
+
};
|
|
120
|
+
presentation: {
|
|
121
|
+
dsh: string;
|
|
122
|
+
newmark: string;
|
|
123
|
+
description: string;
|
|
124
|
+
};
|
|
125
|
+
pluginDiscovery: {
|
|
126
|
+
dsh: string;
|
|
127
|
+
newmark: string;
|
|
128
|
+
description: string;
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
breakingChangeCompat: {
|
|
132
|
+
strategy: string;
|
|
133
|
+
mechanisms: string[];
|
|
134
|
+
boundary: string;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
export interface DshCompatibilitySnapshot {
|
|
138
|
+
id: 'deepseek-harness';
|
|
139
|
+
displayName: 'DeepSeek Harness (DSH)';
|
|
140
|
+
developerPreview: true;
|
|
141
|
+
detected: boolean;
|
|
142
|
+
readOnly: true;
|
|
143
|
+
preservesUnknownFields: true;
|
|
144
|
+
dshHome: string;
|
|
145
|
+
home: {
|
|
146
|
+
path: string;
|
|
147
|
+
source: 'DSH_HOME' | 'default';
|
|
148
|
+
exists: boolean;
|
|
149
|
+
};
|
|
150
|
+
cli: {
|
|
151
|
+
command: 'dsh';
|
|
152
|
+
available: boolean;
|
|
153
|
+
path?: string;
|
|
154
|
+
version?: string;
|
|
155
|
+
packageVersion?: string;
|
|
156
|
+
};
|
|
157
|
+
package: {
|
|
158
|
+
name: '@deepseek-ai/dsh';
|
|
159
|
+
version?: string;
|
|
160
|
+
manifestPath?: string;
|
|
161
|
+
};
|
|
162
|
+
update: {
|
|
163
|
+
package: '@deepseek-ai/dsh';
|
|
164
|
+
channel: 'latest';
|
|
165
|
+
locked: false;
|
|
166
|
+
runCommand: 'npx @deepseek-ai/dsh web';
|
|
167
|
+
pluginCommand: 'dsh plugin --profile <name> add <package>';
|
|
168
|
+
repository: string;
|
|
169
|
+
documentation: string;
|
|
170
|
+
npm: string;
|
|
171
|
+
};
|
|
172
|
+
recognizedManifestKeys: ['dsh.bundle.patch', 'dsh.profile.bundles'];
|
|
173
|
+
profiles: DshProfileSnapshot[];
|
|
174
|
+
bundles: DshBundleSnapshot[];
|
|
175
|
+
mcpCandidates: DshMcpCandidate[];
|
|
176
|
+
configFiles: string[];
|
|
177
|
+
homeConfigFiles: string[];
|
|
178
|
+
unknownKeys: string[];
|
|
179
|
+
warnings: string[];
|
|
180
|
+
scannedAt: string;
|
|
181
|
+
compaction: DshCompactionRuntimeSemantics;
|
|
182
|
+
toolLayer: DshToolLayerRuntimeSemantics;
|
|
183
|
+
}
|
|
184
|
+
export declare function discoverDshCompatibility(root: string, options?: DshCompatibilityOptions): DshCompatibilitySnapshot;
|
|
185
|
+
/**
|
|
186
|
+
* DSH dsh-compaction-basic 运行时 seam 到 Newmark 压缩系统的语义映射。
|
|
187
|
+
* 纯只读元数据:描述 DSH 各运行时入口如何映射到 Newmark 的原生等价实现,
|
|
188
|
+
* 既不 import 也不 execute 任何 DSH 插件代码。
|
|
189
|
+
*/
|
|
190
|
+
export declare function dshCompactionRuntimeSemantics(): DshCompactionRuntimeSemantics;
|
|
191
|
+
/**
|
|
192
|
+
* DSH 工具层的运行时语义映射(纯只读元数据)。
|
|
193
|
+
* 描述 DSH 工具层各 seam 如何映射到 Newmark 原生工具执行层,并声明破坏性
|
|
194
|
+
* developer-preview schema 更新的 fail-soft 兼容策略。既不 import 也不 execute
|
|
195
|
+
* 任何 DSH 插件代码。
|
|
196
|
+
*/
|
|
197
|
+
export declare function dshToolLayerRuntimeSemantics(): DshToolLayerRuntimeSemantics;
|
|
198
|
+
//# sourceMappingURL=dshCompatibility.d.ts.map
|