@zhin.js/agent 1.1.39 → 1.1.41

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 (120) hide show
  1. package/lib/assistant/job-storage.d.ts +238 -0
  2. package/lib/assistant/job-storage.js +143 -0
  3. package/lib/assistant/job-storage.js.map +1 -0
  4. package/lib/assistant/job-store.d.ts +7 -0
  5. package/lib/assistant/job-store.js +41 -3
  6. package/lib/assistant/job-store.js.map +1 -1
  7. package/lib/config/perception-config.d.ts +9 -0
  8. package/lib/config/perception-config.js +27 -0
  9. package/lib/config/perception-config.js.map +1 -1
  10. package/lib/context/context-system.d.ts +1 -0
  11. package/lib/context/context-system.js +8 -8
  12. package/lib/context/context-system.js.map +1 -1
  13. package/lib/context/im-turn-context-adapter.js +2 -0
  14. package/lib/context/im-turn-context-adapter.js.map +1 -1
  15. package/lib/context/skill-context.d.ts +3 -0
  16. package/lib/context/skill-context.js +6 -0
  17. package/lib/context/skill-context.js.map +1 -0
  18. package/lib/context/turn-envelope.d.ts +4 -0
  19. package/lib/context/turn-envelope.js +24 -7
  20. package/lib/context/turn-envelope.js.map +1 -1
  21. package/lib/context/turn-user-message.d.ts +3 -1
  22. package/lib/context/turn-user-message.js +14 -1
  23. package/lib/context/turn-user-message.js.map +1 -1
  24. package/lib/core/agent-core-run.d.ts +1 -0
  25. package/lib/core/agent-core-run.js +47 -20
  26. package/lib/core/agent-core-run.js.map +1 -1
  27. package/lib/core/structured-reply-recovery.d.ts +6 -2
  28. package/lib/core/structured-reply-recovery.js +22 -8
  29. package/lib/core/structured-reply-recovery.js.map +1 -1
  30. package/lib/core/turn-completion-usage.d.ts +2 -1
  31. package/lib/core/turn-completion-usage.js +14 -5
  32. package/lib/core/turn-completion-usage.js.map +1 -1
  33. package/lib/core/turn-event-mapper.d.ts +1 -1
  34. package/lib/core/turn-event-mapper.js +8 -5
  35. package/lib/core/turn-event-mapper.js.map +1 -1
  36. package/lib/decision/config.d.ts +1 -1
  37. package/lib/decision/config.js +1 -1
  38. package/lib/decision/config.js.map +1 -1
  39. package/lib/decision/types.d.ts +1 -1
  40. package/lib/decision/types.js.map +1 -1
  41. package/lib/event/turn-event.d.ts +7 -1
  42. package/lib/event/turn-event.js.map +1 -1
  43. package/lib/index.d.ts +4 -1
  44. package/lib/index.js +2 -0
  45. package/lib/index.js.map +1 -1
  46. package/lib/media/perception.d.ts +3 -4
  47. package/lib/media/perception.js +59 -37
  48. package/lib/media/perception.js.map +1 -1
  49. package/lib/memory/compaction-runtime.d.ts +3 -2
  50. package/lib/memory/compaction-runtime.js +22 -14
  51. package/lib/memory/compaction-runtime.js.map +1 -1
  52. package/lib/outbound/agent-output.js +2 -0
  53. package/lib/outbound/agent-output.js.map +1 -1
  54. package/lib/outbound/chat-failure.d.ts +27 -0
  55. package/lib/outbound/chat-failure.js +53 -0
  56. package/lib/outbound/chat-failure.js.map +1 -0
  57. package/lib/outbound/structured-reply.d.ts +7 -0
  58. package/lib/outbound/structured-reply.js +52 -16
  59. package/lib/outbound/structured-reply.js.map +1 -1
  60. package/lib/plugin-runtime/agent-runtime.js +49 -8
  61. package/lib/plugin-runtime/agent-runtime.js.map +1 -1
  62. package/lib/plugin-runtime/ai-completion.d.ts +4 -3
  63. package/lib/plugin-runtime/ai-completion.js +64 -10
  64. package/lib/plugin-runtime/ai-completion.js.map +1 -1
  65. package/lib/plugin-runtime/capability-ingress.js +3 -1
  66. package/lib/plugin-runtime/capability-ingress.js.map +1 -1
  67. package/lib/plugin-runtime/decision-runtime.d.ts +1 -0
  68. package/lib/plugin-runtime/deferred-capability-plan.d.ts +4 -1
  69. package/lib/plugin-runtime/deferred-capability-plan.js +25 -9
  70. package/lib/plugin-runtime/deferred-capability-plan.js.map +1 -1
  71. package/lib/plugin-runtime/full-agent-turn-engine.js +1 -0
  72. package/lib/plugin-runtime/full-agent-turn-engine.js.map +1 -1
  73. package/lib/plugin-runtime/index.d.ts +2 -0
  74. package/lib/plugin-runtime/index.js +2 -0
  75. package/lib/plugin-runtime/index.js.map +1 -1
  76. package/lib/prompt/assembly.js +0 -9
  77. package/lib/prompt/assembly.js.map +1 -1
  78. package/lib/prompt/git-context.js +1 -1
  79. package/lib/prompt/git-context.js.map +1 -1
  80. package/lib/prompt/rules/chat-rules.js +8 -9
  81. package/lib/prompt/rules/chat-rules.js.map +1 -1
  82. package/lib/prompt/rules/critical-rules.js +10 -10
  83. package/lib/prompt/rules/critical-rules.js.map +1 -1
  84. package/lib/prompt/system-prompt.js +4 -5
  85. package/lib/prompt/system-prompt.js.map +1 -1
  86. package/lib/security/file-role-policy.js +6 -6
  87. package/lib/security/file-role-policy.js.map +1 -1
  88. package/lib/security/policy-facade.js +1 -1
  89. package/lib/security/policy-facade.js.map +1 -1
  90. package/lib/security/usage-quota.d.ts +4 -0
  91. package/lib/security/usage-quota.js +23 -2
  92. package/lib/security/usage-quota.js.map +1 -1
  93. package/lib/session/approval-port.d.ts +2 -0
  94. package/lib/session/approval-port.js.map +1 -1
  95. package/lib/session/approval-review-agent.d.ts +1 -1
  96. package/lib/session/approval-review-agent.js +19 -4
  97. package/lib/session/approval-review-agent.js.map +1 -1
  98. package/lib/session/turn-ingress-session.js +7 -1
  99. package/lib/session/turn-ingress-session.js.map +1 -1
  100. package/lib/tool/tool-approval-gate.js +4 -2
  101. package/lib/tool/tool-approval-gate.js.map +1 -1
  102. package/lib/tool/turn-tool-runtime.js +24 -5
  103. package/lib/tool/turn-tool-runtime.js.map +1 -1
  104. package/lib/tool-catalog/deferred-turn-controller.js +1 -4
  105. package/lib/tool-catalog/deferred-turn-controller.js.map +1 -1
  106. package/lib/trace/context-budget.d.ts +4 -3
  107. package/lib/trace/context-budget.js +28 -8
  108. package/lib/trace/context-budget.js.map +1 -1
  109. package/lib/trace/turn-trace-format.js +4 -1
  110. package/lib/trace/turn-trace-format.js.map +1 -1
  111. package/lib/trace/turn-trace.d.ts +6 -0
  112. package/lib/trace/turn-trace.js +8 -2
  113. package/lib/trace/turn-trace.js.map +1 -1
  114. package/lib/trace/turn-usage-log.d.ts +14 -0
  115. package/lib/trace/turn-usage-log.js +83 -0
  116. package/lib/trace/turn-usage-log.js.map +1 -0
  117. package/lib/usage/usage-store.d.ts +199 -0
  118. package/lib/usage/usage-store.js +121 -0
  119. package/lib/usage/usage-store.js.map +1 -0
  120. package/package.json +12 -12
@@ -5,7 +5,7 @@ import { decodeStructuredReply, structuredReplyInstruction, structuredReplySchem
5
5
  import { renderAgentOutput } from '../outbound/agent-output.js';
6
6
  import { mergeToolOutboundElements } from '../media/media-tool-bridge.js';
7
7
  import { formatCompact, truncatePreview, getLogger } from '@zhin.js/logger';
8
- import { parseOutput, agentLoop, agentContextFrom, assistantText, createUserMessage, agentToolsToLlmTools, createResilientCompletionPort, isProviderFailureMessage, resolveProviderConfigResilience, resolveProviderResilienceConfig } from '@zhin.js/ai';
8
+ import { createPromptContextBlock, projectPromptContext, estimateContextFixedTokens, parseOutput, agentLoop, agentContextFrom, assistantText, createUserMessage, agentToolsToLlmTools, createResilientCompletionPort, isProviderFailureMessage, resolveProviderConfigResilience, resolveProviderResilienceConfig } from '@zhin.js/ai';
9
9
  import { tokenUsageToLegacy } from './agent-run-shared.js';
10
10
  import { applyExecPolicyToTools } from '../security/exec-policy.js';
11
11
  import { resolveModelHarness } from '../config/model-harness-runtime.js';
@@ -15,7 +15,8 @@ import { planToolRun } from '../tool/runtime.js';
15
15
  import { sanitizeAssistantReply, unwrapJsonStringLayers } from './text-sanitize.js';
16
16
  import { formatToolCallsForUser } from './tool-calls-user-format.js';
17
17
  import { summarizeExhaustedTurn } from './exhausted-turn-reply.js';
18
- import { decodeLenientStructuredReply, recoverStructuredReply, STRUCTURED_REPLY_FAILURE } from './structured-reply-recovery.js';
18
+ import { decodeLenientStructuredReply, recoverStructuredReply } from './structured-reply-recovery.js';
19
+ import { chatFailureKindOf, chatFailureLine } from '../outbound/chat-failure.js';
19
20
  import { trackTurnCompletionUsage } from './turn-completion-usage.js';
20
21
  import { shouldSuppressReplyForSpawnDelegation } from './spawn-delegation.js';
21
22
  import { logPhase, tokenUsageLogFields, logAgentLoopIterationEnd } from '../internal/phase-trace.js';
@@ -24,7 +25,7 @@ import { buildLlmToolsForProvider } from '../tool/deferred-resolution.js';
24
25
  import { applyToolToModelOutput } from '../tool/tool-model-output.js';
25
26
  import { resolveAlwaysLoadedSet } from '../tool-catalog/resolve-config.js';
26
27
  import { resolveDeferredApiTools, residentToolNames } from '../tool-catalog/tool-catalog.js';
27
- import { createTurnEventMapperState, mapAgentEventToTurnEvents, turnUsageEvent, } from './turn-event-mapper.js';
28
+ import { createTurnEventMapperState, mapAgentEventToTurnEvents, } from './turn-event-mapper.js';
28
29
  import { TurnJournalCommitError } from '../turn/journal-integrity.js';
29
30
  import { ExecutableToolRegistry } from '../tool/executable-tool-registry.js';
30
31
  import { withoutForbiddenShell } from '../plugin-runtime/native-bash-tool.js';
@@ -33,7 +34,6 @@ import { createMissingToolResolver } from './missing-tool-resolver.js';
33
34
  import { DEFAULT_EXPLORATION_BUDGET, EXPLORATION_GUIDANCE, ExplorationBudget, } from './exploration-budget.js';
34
35
  import { TurnProgressTracker, autoContinueAllowed, buildContinuationInstruction, isProgress, resolveToolBudget, } from './turn-progress.js';
35
36
  import { TurnProgressReporter, summarizeProgress } from './progress-reporter.js';
36
- import { estimatePromptTokens } from '../prompt/estimate-tokens.js';
37
37
  import { noteTurnTrace } from '../trace/turn-trace-registry.js';
38
38
  import { buildContextBudgetReport } from '../trace/context-budget.js';
39
39
  import { renderDeferredToolIndex } from '../skill/capability-catalog.js';
@@ -46,11 +46,14 @@ function normalizeAssistantMessageText(assistant) {
46
46
  }
47
47
  }
48
48
  }
49
- function resolveAssistantReplyText(assistant) {
49
+ function resolveAssistantReplyText(assistant, chat) {
50
50
  normalizeAssistantMessageText(assistant);
51
51
  const text = assistantText(assistant);
52
52
  if (text.trim())
53
53
  return text;
54
+ // In a chat the failure is said like a member would say it; operators read the logs.
55
+ if (assistant.errorMessage && chat)
56
+ return chatFailureLine(chatFailureKindOf(assistant.errorMessage), chat);
54
57
  if (assistant.errorMessage && isProviderFailureMessage(assistant.errorMessage)) {
55
58
  return `${assistant.errorMessage}。`;
56
59
  }
@@ -184,7 +187,7 @@ async function* runAgentLoopVisionTurnOnceRun(input) {
184
187
  modelId,
185
188
  label: 'vision',
186
189
  }),
187
- convertToLlm: (messages) => messages,
190
+ convertToLlm: projectPromptContext,
188
191
  getSteeringMessages: promptHooks?.getSteeringMessages,
189
192
  getFollowUpMessages: promptHooks?.getFollowUpMessages,
190
193
  };
@@ -320,7 +323,7 @@ export async function* runAgentLoopTextTurnRun(input) {
320
323
  const loaded = persistentConversation
321
324
  ? await repo.loadContext(sessionId)
322
325
  : { messages: [] };
323
- const promptMessages = input.initialMessages?.length
326
+ let promptMessages = input.initialMessages?.length
324
327
  ? input.initialMessages
325
328
  : [createUserMessage(input.rawContent)];
326
329
  const directTools = input.toolLoading === 'direct';
@@ -336,6 +339,9 @@ export async function* runAgentLoopTextTurnRun(input) {
336
339
  const messagePreset = configuredSchema === true || configuredSchema === 'segments';
337
340
  const imReply = messagePreset && input.turnContext.origin.kind === 'im'
338
341
  && input.conversationPersistence !== 'none';
342
+ const chatFailure = input.turnContext.origin.kind === 'im'
343
+ ? { master: input.turnContext.principal.roles.includes('master') }
344
+ : undefined;
339
345
  const outputSchema = imReply ? structuredReplySchema(input.replySegments)
340
346
  : messagePreset || !configuredSchema ? undefined : configuredSchema;
341
347
  const turnShellPolicy = input.turnContext.policy?.shell;
@@ -433,8 +439,15 @@ export async function* runAgentLoopTextTurnRun(input) {
433
439
  if (hasTools && !directTools) {
434
440
  const toolIndex = renderDeferredToolIndex(deferredCatalogTools(catalog, agentTools)
435
441
  .map((item) => ({ name: item.name, description: item.brief })));
436
- if (toolIndex)
437
- systemPrompt = `${systemPrompt}\n\n${toolIndex}`;
442
+ if (toolIndex) {
443
+ const block = createPromptContextBlock('deferred-tools', toolIndex);
444
+ const userIndex = promptMessages.map(message => message.role === 'user' && Array.isArray(message.content)).lastIndexOf(true);
445
+ promptMessages = userIndex < 0
446
+ ? [...promptMessages, { ...createUserMessage(''), content: [block] }]
447
+ : promptMessages.map((message, index) => index === userIndex && Array.isArray(message.content)
448
+ ? { ...message, content: [...message.content, block] }
449
+ : message);
450
+ }
438
451
  }
439
452
  if (networkWithheld)
440
453
  systemPrompt = `${systemPrompt}\n\n${NETWORK_DISABLED_PROMPT_NOTE}`;
@@ -447,6 +460,7 @@ export async function* runAgentLoopTextTurnRun(input) {
447
460
  kind: 'context_budget',
448
461
  report: buildContextBudgetReport({
449
462
  systemPrompt,
463
+ outputSchema,
450
464
  sections: promptSections,
451
465
  bootstrapContext: input.promptRuntime?.bootstrapContext,
452
466
  activeSkillsContext: input.promptRuntime?.activeSkillsContext,
@@ -490,8 +504,16 @@ export async function* runAgentLoopTextTurnRun(input) {
490
504
  const contextWindow = llmModel.contextWindow ?? host.config.contextTokens;
491
505
  // System prompt and tool schemas count against the window too, so the
492
506
  // compaction threshold is measured on what is left for messages (#730).
493
- const fixedPromptTokens = () => estimatePromptTokens(systemPrompt)
494
- + llmTools.reduce((sum, tool) => sum + estimatePromptTokens(`${tool.name} ${tool.description}`), 0);
507
+ let budgetTools;
508
+ let fixedBudget;
509
+ const fixedPromptTokens = () => {
510
+ // 本回合系统提示不变;工具渐进披露替换数组后重新计算完整 Schema。
511
+ if (!fixedBudget || budgetTools !== llmTools) {
512
+ budgetTools = llmTools;
513
+ fixedBudget = estimateContextFixedTokens({ systemPrompt, tools: llmTools, model: llmModel, outputSchema });
514
+ }
515
+ return fixedBudget;
516
+ };
495
517
  const loopHooks = input.loopHooks;
496
518
  const completionPort = createTurnCompletionPort({
497
519
  host,
@@ -544,7 +566,7 @@ export async function* runAgentLoopTextTurnRun(input) {
544
566
  }),
545
567
  ...(outputSchema ? { outputSchema } : {}),
546
568
  },
547
- convertToLlm: (messages) => messages,
569
+ convertToLlm: projectPromptContext,
548
570
  transformContext: async (messages, ctxSignal) => persistentConversation ? host.compactionRuntime.transformContext(messages, ctxSignal, {
549
571
  host,
550
572
  sessionId,
@@ -552,7 +574,7 @@ export async function* runAgentLoopTextTurnRun(input) {
552
574
  model: llmModel,
553
575
  compactionConfig: host.config.compaction,
554
576
  contextWindow,
555
- reservedTokens: fixedPromptTokens(),
577
+ reservedTokens: await fixedPromptTokens(),
556
578
  toldLedger: host.toldLedger?.render(sessionId),
557
579
  mode: 'text',
558
580
  loopHooks,
@@ -564,7 +586,7 @@ export async function* runAgentLoopTextTurnRun(input) {
564
586
  model: llmModel,
565
587
  compactionConfig: host.config.compaction,
566
588
  contextWindow,
567
- reservedTokens: fixedPromptTokens(),
589
+ reservedTokens: await fixedPromptTokens(),
568
590
  toldLedger: host.toldLedger?.render(sessionId),
569
591
  mode: 'text',
570
592
  force: true,
@@ -644,7 +666,9 @@ export async function* runAgentLoopTextTurnRun(input) {
644
666
  const budgetNote = explorationBudget?.record(resolvedName, isProgress(progressKind));
645
667
  const finalText = budgetNote ? `${resultText}\n\n${budgetNote}` : resultText;
646
668
  toolCalls.push({ tool: resolvedName, args: effectiveArgs, result: finalText });
647
- return toolResultToAgentMessage(toolCall, finalText, false);
669
+ const result = toolResultToAgentMessage(toolCall, finalText, false);
670
+ const blocks = deferredController?.modelOutputBlocks?.(resolvedName, effectiveArgs, finalText);
671
+ return blocks ? { ...result, content: blocks } : result;
648
672
  }
649
673
  catch (err) {
650
674
  if (err instanceof TurnJournalCommitError)
@@ -719,8 +743,7 @@ export async function* runAgentLoopTextTurnRun(input) {
719
743
  // Messages of the running segment, for progress summaries before agent_end.
720
744
  let segmentMessages = [];
721
745
  function* drainCompletionUsage() {
722
- for (const usage of completionUsage.drainUsage()) {
723
- const event = turnUsageEvent(usage);
746
+ for (const event of completionUsage.drainEvents()) {
724
747
  emitTurnEvent(event);
725
748
  yield event;
726
749
  }
@@ -773,7 +796,7 @@ export async function* runAgentLoopTextTurnRun(input) {
773
796
  lastAssistantNeedsHostReply = Boolean(assistant.errorMessage)
774
797
  || (!lastAssistantHadToolCalls && !answerText.trim());
775
798
  lastAssistantText = imReply && !lastAssistantNeedsHostReply ? answerText
776
- : resolveAssistantReplyText(imReply ? { ...assistant, content: [] } : assistant);
799
+ : resolveAssistantReplyText(imReply ? { ...assistant, content: [] } : assistant, chatFailure);
777
800
  logAssistantIterationFailure(assistant, modelId, sessionId);
778
801
  const toolNames = assistant.content
779
802
  .filter((b) => b.type === 'toolCall')
@@ -904,7 +927,10 @@ export async function* runAgentLoopTextTurnRun(input) {
904
927
  const continuationPrefix = continuations > 0 && input.turnContext.origin.kind !== 'im'
905
928
  ? `(任务步骤较多,已自动续跑 ${continuations} 次)\n\n` : '';
906
929
  const proseReply = structuredReply ? ''
907
- : sanitizeAssistantReply(rawReply, { toolSummary: formatToolCallsForUser(toolCalls) });
930
+ : sanitizeAssistantReply(rawReply, {
931
+ toolSummary: formatToolCallsForUser(toolCalls),
932
+ ...(chatFailure ? { emptyMessage: chatFailureLine('malformed_tool_call', chatFailure) } : {}),
933
+ });
908
934
  const textReply = delegatedOnly ? '' : proseReply.trim() ? continuationPrefix + proseReply : proseReply;
909
935
  let output = delegatedOnly || structuredReply ? [] : parseOutput(textReply);
910
936
  if (!delegatedOnly && structuredReply) {
@@ -926,13 +952,14 @@ export async function* runAgentLoopTextTurnRun(input) {
926
952
  transport: completionUsage.transport, model: llmModel, raw: rawReply,
927
953
  error: error instanceof Error ? error : new Error('Invalid structured reply'), signal,
928
954
  segments: input.replySegments,
955
+ failureText: chatFailureLine('format', { ...chatFailure, random: 0 }),
929
956
  });
930
957
  output = recovery.output;
931
958
  // History must match what the user saw: the corrected reply, or the failure text. Never the
932
959
  // correction prompt (it embeds the rejected raw text) and never the rejected raw reply.
933
960
  if (messages && rejected?.role === 'assistant') {
934
961
  messages[messages.length - 1] = recovery.assistant
935
- ?? { ...rejected, content: [{ type: 'text', text: STRUCTURED_REPLY_FAILURE }] };
962
+ ?? { ...rejected, content: [{ type: 'text', text: renderAgentOutput(recovery.output) }] };
936
963
  }
937
964
  }
938
965
  }