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.
Files changed (60) hide show
  1. package/dist/cli-commands.d.ts +1 -0
  2. package/dist/cli-commands.js +11 -2
  3. package/dist/context/domain/types.d.ts +37 -0
  4. package/dist/context/services/context-orchestrator.js +2 -0
  5. package/dist/conversation-utility-host.bundle.cjs +1259 -132
  6. package/dist/conversation-utility-host.js +3 -0
  7. package/dist/core/agent.d.ts +139 -5
  8. package/dist/core/agent.js +964 -82
  9. package/dist/core/agentKernel/agent-loop.js +29 -3
  10. package/dist/core/agentKernel/types.d.ts +7 -0
  11. package/dist/core/agentKernelRunner.d.ts +2 -0
  12. package/dist/core/agentKernelRunner.js +121 -19
  13. package/dist/core/conversationKernel.d.ts +5 -0
  14. package/dist/core/conversationKernel.js +29 -0
  15. package/dist/core/dshCompatibility.d.ts +198 -0
  16. package/dist/core/dshCompatibility.js +600 -0
  17. package/dist/core/electronUtilityAgentClient.d.ts +4 -0
  18. package/dist/core/electronUtilityAgentClient.js +4 -0
  19. package/dist/core/electronUtilityRuntimePool.d.ts +8 -0
  20. package/dist/core/electronUtilityRuntimePool.js +14 -0
  21. package/dist/core/mcpManager.d.ts +1 -0
  22. package/dist/core/mcpManager.js +100 -10
  23. package/dist/core/subagent.d.ts +6 -0
  24. package/dist/core/subagent.js +22 -1
  25. package/dist/core/toolPolicy.d.ts +15 -0
  26. package/dist/core/toolPolicy.js +174 -1
  27. package/dist/core/types.d.ts +1 -1
  28. package/dist/core/utilityAgentProtocol.d.ts +8 -1
  29. package/dist/core/workspace.d.ts +9 -0
  30. package/dist/core/workspace.js +48 -1
  31. package/dist/core/wslAgentClient.d.ts +4 -0
  32. package/dist/core/wslAgentClient.js +4 -0
  33. package/dist/core/wslAgentProtocol.d.ts +8 -1
  34. package/dist/core/wslAgentRuntimePool.d.ts +8 -0
  35. package/dist/core/wslAgentRuntimePool.js +15 -0
  36. package/dist/launcher.js +8 -0
  37. package/dist/llm/provider.d.ts +1 -1
  38. package/dist/llm/provider.js +4 -3
  39. package/dist/main.js +163 -11
  40. package/dist/preload.js +11 -0
  41. package/dist/providers/chat-completions.adapter.js +41 -15
  42. package/dist/providers/provider-adapter.d.ts +3 -0
  43. package/dist/toolchain/registry/tool-registry.d.ts +13 -1
  44. package/dist/toolchain/registry/tool-registry.js +8 -0
  45. package/dist/toolchain/registry-seeder.js +52 -6
  46. package/dist/tools/index.d.ts +1 -0
  47. package/dist/tools/index.js +39 -2
  48. package/dist/tools/nativeTools.js +6 -1
  49. package/dist/tui/src/app.js +24 -0
  50. package/dist/tui/src/i18n.js +151 -0
  51. package/dist/tui/src/render.js +152 -61
  52. package/dist/tui/src/state.js +83 -0
  53. package/dist/ui/index.html +2669 -234
  54. package/dist/ui/lucide-sprite.svg +31 -0
  55. package/dist/wsl-agent-host.bundle.cjs +1259 -132
  56. package/dist/wsl-agent-host.js +3 -0
  57. package/package.json +6 -10
  58. package/Flow/Electron-Debug-Release.Flow.json +0 -43
  59. package/Flow/Flow.md +0 -9
  60. 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
- // Promise.all is the batch barrier: every launch succeeds or fails before
197
- // the provider receives any result and starts the next reasoning step.
198
- return await Promise.all(toolCalls.map(call => executeOne(call)));
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
- buildRequestTaskFocus(currentAgent, context.messages, {
520
- includeBootstrap,
521
- compressionCompleted,
522
- activeTools: context.tools || [],
523
- toolCatalog: currentAgent.cachedToolDefinitions(),
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
- const compressionSummary = options.compressionCompleted
733
- ? compactTaskLedgerText(agent.lastCompression?.summary || '(compression summary unavailable)', 4000)
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
- options.compressionCompleted
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
- options.compressionCompleted
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: String(fn.name || ''),
1339
- label: String(fn.name || ''),
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