@zhin.js/agent 1.1.38 → 1.1.40
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/lib/assistant/job-engine.d.ts +5 -0
- package/lib/assistant/job-engine.js +20 -1
- package/lib/assistant/job-engine.js.map +1 -1
- package/lib/assistant/job-storage.d.ts +238 -0
- package/lib/assistant/job-storage.js +143 -0
- package/lib/assistant/job-storage.js.map +1 -0
- package/lib/assistant/job-store.d.ts +7 -0
- package/lib/assistant/job-store.js +41 -3
- package/lib/assistant/job-store.js.map +1 -1
- package/lib/config/perception-config.d.ts +9 -0
- package/lib/config/perception-config.js +27 -0
- package/lib/config/perception-config.js.map +1 -1
- package/lib/context/context-system.d.ts +1 -0
- package/lib/context/context-system.js +8 -8
- package/lib/context/context-system.js.map +1 -1
- package/lib/context/im-turn-context-adapter.js +2 -0
- package/lib/context/im-turn-context-adapter.js.map +1 -1
- package/lib/context/index.d.ts +1 -1
- package/lib/context/index.js +1 -1
- package/lib/context/index.js.map +1 -1
- package/lib/context/skill-context.d.ts +3 -0
- package/lib/context/skill-context.js +6 -0
- package/lib/context/skill-context.js.map +1 -0
- package/lib/context/turn-envelope.d.ts +7 -1
- package/lib/context/turn-envelope.js +30 -7
- package/lib/context/turn-envelope.js.map +1 -1
- package/lib/context/turn-user-message.d.ts +3 -1
- package/lib/context/turn-user-message.js +14 -1
- package/lib/context/turn-user-message.js.map +1 -1
- package/lib/core/agent-core-run.d.ts +1 -0
- package/lib/core/agent-core-run.js +68 -34
- package/lib/core/agent-core-run.js.map +1 -1
- package/lib/core/structured-reply-recovery.d.ts +13 -0
- package/lib/core/structured-reply-recovery.js +41 -5
- package/lib/core/structured-reply-recovery.js.map +1 -1
- package/lib/core/turn-completion-usage.d.ts +2 -1
- package/lib/core/turn-completion-usage.js +14 -5
- package/lib/core/turn-completion-usage.js.map +1 -1
- package/lib/core/turn-event-mapper.d.ts +1 -1
- package/lib/core/turn-event-mapper.js +8 -5
- package/lib/core/turn-event-mapper.js.map +1 -1
- package/lib/event/turn-event.d.ts +7 -1
- package/lib/event/turn-event.js.map +1 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/media/perception.d.ts +3 -4
- package/lib/media/perception.js +59 -37
- package/lib/media/perception.js.map +1 -1
- package/lib/memory/compaction-runtime.d.ts +3 -2
- package/lib/memory/compaction-runtime.js +22 -14
- package/lib/memory/compaction-runtime.js.map +1 -1
- package/lib/outbound/agent-output.js +2 -0
- package/lib/outbound/agent-output.js.map +1 -1
- package/lib/outbound/chat-failure.d.ts +27 -0
- package/lib/outbound/chat-failure.js +53 -0
- package/lib/outbound/chat-failure.js.map +1 -0
- package/lib/outbound/structured-reply.d.ts +7 -0
- package/lib/outbound/structured-reply.js +72 -16
- package/lib/outbound/structured-reply.js.map +1 -1
- package/lib/plugin-runtime/agent-runtime.js +49 -8
- package/lib/plugin-runtime/agent-runtime.js.map +1 -1
- package/lib/plugin-runtime/ai-completion.d.ts +4 -3
- package/lib/plugin-runtime/ai-completion.js +64 -10
- package/lib/plugin-runtime/ai-completion.js.map +1 -1
- package/lib/plugin-runtime/capability-ingress.js +3 -1
- package/lib/plugin-runtime/capability-ingress.js.map +1 -1
- package/lib/plugin-runtime/deferred-capability-plan.d.ts +4 -1
- package/lib/plugin-runtime/deferred-capability-plan.js +25 -9
- package/lib/plugin-runtime/deferred-capability-plan.js.map +1 -1
- package/lib/plugin-runtime/full-agent-turn-engine.js +1 -0
- package/lib/plugin-runtime/full-agent-turn-engine.js.map +1 -1
- package/lib/plugin-runtime/index.d.ts +2 -0
- package/lib/plugin-runtime/index.js +2 -0
- package/lib/plugin-runtime/index.js.map +1 -1
- package/lib/prompt/assembly.js +0 -9
- package/lib/prompt/assembly.js.map +1 -1
- package/lib/prompt/git-context.js +1 -1
- package/lib/prompt/git-context.js.map +1 -1
- package/lib/prompt/rules/chat-rules.js +8 -9
- package/lib/prompt/rules/chat-rules.js.map +1 -1
- package/lib/prompt/rules/critical-rules.js +10 -10
- package/lib/prompt/rules/critical-rules.js.map +1 -1
- package/lib/prompt/system-prompt.js +4 -5
- package/lib/prompt/system-prompt.js.map +1 -1
- package/lib/security/file-role-policy.js +6 -6
- package/lib/security/file-role-policy.js.map +1 -1
- package/lib/security/policy-facade.js +1 -1
- package/lib/security/policy-facade.js.map +1 -1
- package/lib/security/usage-quota.d.ts +4 -0
- package/lib/security/usage-quota.js +23 -2
- package/lib/security/usage-quota.js.map +1 -1
- package/lib/session/approval-port.d.ts +2 -0
- package/lib/session/approval-port.js.map +1 -1
- package/lib/session/approval-review-agent.d.ts +1 -1
- package/lib/session/approval-review-agent.js +19 -4
- package/lib/session/approval-review-agent.js.map +1 -1
- package/lib/session/turn-ingress-session.js +7 -1
- package/lib/session/turn-ingress-session.js.map +1 -1
- package/lib/tool/tool-approval-gate.js +4 -2
- package/lib/tool/tool-approval-gate.js.map +1 -1
- package/lib/tool/turn-tool-runtime.js +24 -5
- package/lib/tool/turn-tool-runtime.js.map +1 -1
- package/lib/tool-catalog/deferred-turn-controller.js +1 -4
- package/lib/tool-catalog/deferred-turn-controller.js.map +1 -1
- package/lib/trace/context-budget.d.ts +4 -3
- package/lib/trace/context-budget.js +28 -8
- package/lib/trace/context-budget.js.map +1 -1
- package/lib/trace/turn-trace-format.js +4 -1
- package/lib/trace/turn-trace-format.js.map +1 -1
- package/lib/trace/turn-trace.d.ts +6 -0
- package/lib/trace/turn-trace.js +8 -2
- package/lib/trace/turn-trace.js.map +1 -1
- package/lib/trace/turn-usage-log.d.ts +14 -0
- package/lib/trace/turn-usage-log.js +83 -0
- package/lib/trace/turn-usage-log.js.map +1 -0
- package/lib/usage/usage-store.d.ts +199 -0
- package/lib/usage/usage-store.js +121 -0
- package/lib/usage/usage-store.js.map +1 -0
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-envelope.js","sourceRoot":"","sources":["../../src/context/turn-envelope.ts"],"names":[],"mappings":"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","sourcesContent":["import { getFileMemoryContext, formatMemoryPathsHint } from '../memory-layers.js';\nimport type { TurnRequest } from '../turn/turn-ingress.js';\n\nexport const TURN_CONTEXT_BEGIN = '[Turn context]';\nexport const TURN_CONTEXT_END = '[/Turn context]';\n\nexport type TurnContextView = Pick<TurnRequest, 'origin' | 'principal' | 'session'>\n & Partial<Pick<TurnRequest, 'policy'>>;\n\nexport interface TurnContextEnvelopeInput {\n turn?: TurnContextView;\n profileSummary?: string;\n toneHint?: string;\n deferredStats?: string;\n activeSkillsContext?: string;\n quoteSystemHint?: string;\n modelLine?: string;\n sdk?: string;\n agentsContext?: string;\n /** Rendered \"already told the user\" ledger (#730). */\n toldLedger?: string;\n /** BM25-recalled semantic memory for this message (#734). */\n relevantMemory?: string;\n}\n\nexport function formatSessionContextLine(turn: TurnContextView): string {\n const origin = turn.origin;\n if (origin.kind === 'im') {\n return `Session: platform:${origin.platform} | endpoint:${origin.endpoint} | ${origin.scope}_id:${origin.sceneId}`;\n }\n if (origin.kind === 'http') return `Session: origin:http | session_id:${origin.sessionId}`;\n if (origin.kind === 'a2a') return `Session: origin:a2a | task_id:${origin.taskId}`;\n if (origin.kind === 'schedule') return `Session: origin:schedule | job_id:${origin.jobId}`;\n return `Session: origin:internal | source:${origin.source}`;\n}\n\nexport function formatSenderContextLine(turn: TurnContextView): string {\n const { principal } = turn;\n const roles = principal.roles.length > 0 ? principal.roles.join(',') : 'user';\n return principal.displayName?.trim()\n ? `Sender: id=${principal.subjectId} name=${principal.displayName.trim()} roles=${roles}`\n : `Sender: id=${principal.subjectId} roles=${roles}`;\n}\n\nexport function buildTurnContextEnvelope(input: TurnContextEnvelopeInput): string | null {\n const lines: string[] = [];\n const now = new Date();\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;\n const timeStr = now.toLocaleString('zh-CN', { timeZone: tz });\n lines.push(`Time: ${timeStr} (${tz})`);\n\n if (input.modelLine?.trim()) lines.push(`Model: ${input.modelLine.trim()}`);\n if (input.sdk?.trim()) lines.push(`Sdk: ${input.sdk.trim()}`);\n\n if (input.turn) {\n lines.push(formatSessionContextLine(input.turn));\n lines.push(formatSenderContextLine(input.turn));\n if (input.turn.policy?.filesystem) {\n const filesystem = input.turn.policy.filesystem;\n lines.push(`Workspace: ${filesystem.workingDirectory ?? filesystem.workspaceRoot} | access:${filesystem.access ?? 'workspace-write'}`);\n }\n if (input.turn.origin.kind === 'im') {\n const platform = input.turn.origin.platform;\n const sessionKey = input.turn.session.key;\n const memoryPaths = formatMemoryPathsHint(platform, sessionKey);\n if (memoryPaths) lines.push(`Memory paths: ${memoryPaths}`);\n const fileMemory = getFileMemoryContext(undefined, platform, sessionKey);\n if (fileMemory?.trim()) {\n lines.push('Memory snapshot:');\n lines.push(fileMemory.trim());\n }\n }\n }\n\n if (input.deferredStats?.trim()) lines.push(`Deferred catalog: ${input.deferredStats.trim()}`);\n if (input.profileSummary?.trim()) lines.push(input.profileSummary.trim());\n if (input.toneHint?.trim()) lines.push(`[Tone hint] ${input.toneHint.trim()}`);\n if (input.activeSkillsContext?.trim()) lines.push(input.activeSkillsContext.trim());\n if (input.quoteSystemHint?.trim()) lines.push(input.quoteSystemHint.trim());\n if (input.agentsContext?.trim()) lines.push(input.agentsContext.trim());\n if (input.toldLedger?.trim()) lines.push(input.toldLedger.trim());\n if (input.relevantMemory?.trim()) lines.push(input.relevantMemory.trim());\n\n return lines.length === 0\n ? null\n : `${TURN_CONTEXT_BEGIN}\\n${lines.join('\\n')}\\n${TURN_CONTEXT_END}`;\n}\n\nexport function prependTurnContextEnvelope(content: string, envelope: string | null | undefined): string {\n if (!envelope?.trim()) return content;\n return `${envelope.trim()}\\n\\n${content}`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"turn-envelope.js","sourceRoot":"","sources":["../../src/context/turn-envelope.ts"],"names":[],"mappings":"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","sourcesContent":["import { createPromptContextBlock, type TextContentBlock } from '@zhin.js/ai';\nimport { getFileMemoryContext, formatMemoryPathsHint } from '../memory-layers.js';\nimport type { TurnRequest } from '../turn/turn-ingress.js';\n\nexport const TURN_CONTEXT_BEGIN = '[Turn context]';\nexport const TURN_CONTEXT_END = '[/Turn context]';\n\nexport type TurnContextView = Pick<TurnRequest, 'origin' | 'principal' | 'session'>\n & Partial<Pick<TurnRequest, 'policy' | 'input'>>;\n\n/** Trusted turn metadata key the IM ingress sets for a turn nobody addressed. */\nexport const AMBIENT_ENGAGEMENT_METADATA_KEY = 'zhinEngagement';\n\nconst AMBIENT_ENGAGEMENT_LINE = 'Engagement: ambient. Nobody called you; you are reading the group chat and chose to look. '\n + 'Reply only if a group member like you would naturally chime in here; otherwise return {\"messages\":[]} and stay quiet.';\n\nexport interface TurnContextEnvelopeInput {\n turn?: TurnContextView;\n profileSummary?: string;\n toneHint?: string;\n deferredStats?: string;\n activeSkillsContext?: string;\n activeSkillBlocks?: readonly TextContentBlock[];\n quoteSystemHint?: string;\n modelLine?: string;\n sdk?: string;\n gitStatus?: string | null;\n agentsContext?: string;\n /** Rendered \"already told the user\" ledger (#730). */\n toldLedger?: string;\n /** BM25-recalled semantic memory for this message (#734). */\n relevantMemory?: string;\n}\n\nexport function formatSessionContextLine(turn: TurnContextView): string {\n const origin = turn.origin;\n if (origin.kind === 'im') {\n return `Session: platform:${origin.platform} | endpoint:${origin.endpoint} | ${origin.scope}_id:${origin.sceneId}`;\n }\n if (origin.kind === 'http') return `Session: origin:http | session_id:${origin.sessionId}`;\n if (origin.kind === 'a2a') return `Session: origin:a2a | task_id:${origin.taskId}`;\n if (origin.kind === 'schedule') return `Session: origin:schedule | job_id:${origin.jobId}`;\n return `Session: origin:internal | source:${origin.source}`;\n}\n\nexport function formatSenderContextLine(turn: TurnContextView): string {\n const { principal } = turn;\n const roles = principal.roles.length > 0 ? principal.roles.join(',') : 'user';\n return principal.displayName?.trim()\n ? `Sender: id=${principal.subjectId} name=${principal.displayName.trim()} roles=${roles}`\n : `Sender: id=${principal.subjectId} roles=${roles}`;\n}\n\nexport function buildTurnContextEnvelope(input: TurnContextEnvelopeInput): string | null {\n return buildTurnContextBlocks(input).map(block => block.text).join('\\n');\n}\n\nexport function buildTurnContextBlocks(input: TurnContextEnvelopeInput): TextContentBlock[] {\n const blocks: TextContentBlock[] = [];\n const lines: string[] = [TURN_CONTEXT_BEGIN];\n const flush = () => {\n if (lines.length) blocks.push({ type: 'text', text: lines.splice(0).join('\\n') });\n };\n const now = new Date();\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;\n const timeStr = now.toLocaleString('zh-CN', { timeZone: tz });\n lines.push(`Time: ${timeStr} (${tz})`);\n\n if (input.modelLine?.trim()) lines.push(`Model: ${input.modelLine.trim()}`);\n if (input.sdk?.trim()) lines.push(`Sdk: ${input.sdk.trim()}`);\n if (input.gitStatus?.trim()) lines.push(input.gitStatus.trim());\n\n if (input.turn) {\n lines.push(formatSessionContextLine(input.turn));\n lines.push(formatSenderContextLine(input.turn));\n if (input.turn.input?.metadata?.[AMBIENT_ENGAGEMENT_METADATA_KEY] === 'ambient') lines.push(AMBIENT_ENGAGEMENT_LINE);\n if (input.turn.policy?.filesystem) {\n const filesystem = input.turn.policy.filesystem;\n lines.push(`Workspace: ${filesystem.workingDirectory ?? filesystem.workspaceRoot} | access:${filesystem.access ?? 'workspace-write'}`);\n }\n if (input.turn.origin.kind === 'im') {\n const platform = input.turn.origin.platform;\n const sessionKey = input.turn.session.key;\n const memoryPaths = formatMemoryPathsHint(platform, sessionKey);\n if (memoryPaths) lines.push(`Memory paths: ${memoryPaths}`);\n const fileMemory = getFileMemoryContext(undefined, platform, sessionKey);\n if (fileMemory?.trim()) {\n lines.push('Memory snapshot:');\n lines.push(fileMemory.trim());\n }\n }\n }\n\n if (input.deferredStats?.trim()) lines.push(`Deferred catalog: ${input.deferredStats.trim()}`);\n if (input.profileSummary?.trim()) lines.push(input.profileSummary.trim());\n if (input.toneHint?.trim()) lines.push(`[Tone hint] ${input.toneHint.trim()}`);\n if (input.activeSkillBlocks?.length) {\n flush();\n blocks.push(...input.activeSkillBlocks);\n } else if (input.activeSkillsContext?.trim()) lines.push(input.activeSkillsContext.trim());\n if (input.quoteSystemHint?.trim()) lines.push(input.quoteSystemHint.trim());\n if (input.agentsContext?.trim()) {\n flush();\n blocks.push(createPromptContextBlock('workspace-rules', input.agentsContext.trim()));\n }\n if (input.toldLedger?.trim()) lines.push(input.toldLedger.trim());\n if (input.relevantMemory?.trim()) lines.push(input.relevantMemory.trim());\n\n lines.push(TURN_CONTEXT_END);\n flush();\n return blocks;\n}\n\nexport function prependTurnContextEnvelope(content: string, envelope: string | null | undefined): string {\n if (!envelope?.trim()) return content;\n return `${envelope.trim()}\\n\\n${content}`;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentMessageExtra, type AgentMessage, type UserMessage } from '@zhin.js/ai';
|
|
1
|
+
import { type AgentMessageExtra, type AgentMessage, type UserMessage, type TextContentBlock } from '@zhin.js/ai';
|
|
2
2
|
import type { Message } from '@zhin.js/core';
|
|
3
3
|
export declare function buildTurnUserMessages(commMessage: Message, rawContent: string): {
|
|
4
4
|
rawContent: string;
|
|
@@ -7,3 +7,5 @@ export declare function buildTurnUserMessages(commMessage: Message, rawContent:
|
|
|
7
7
|
};
|
|
8
8
|
export declare function applyTurnContextToUserMessages(messages: UserMessage[], envelope: string | null | undefined): UserMessage[];
|
|
9
9
|
export declare function prependEnvelopeToFirstUserText(messages: AgentMessage[], envelope: string | null | undefined): AgentMessage[];
|
|
10
|
+
/** Keep provenance-bearing guidance separate from the actual participant text. */
|
|
11
|
+
export declare function prependTurnContextBlocks(messages: AgentMessage[], blocks: readonly TextContentBlock[], extra?: AgentMessageExtra): AgentMessage[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createUserMessage, userMessagePlainText } from '@zhin.js/ai';
|
|
1
|
+
import { createUserMessage, userMessagePlainText, userMessageBody, renderUserMessageForLlm } from '@zhin.js/ai';
|
|
2
2
|
import { resolveTurnUserMessage } from '../session/session-io.js';
|
|
3
3
|
import { prependTurnContextEnvelope } from './turn-envelope.js';
|
|
4
4
|
export function buildTurnUserMessages(commMessage, rawContent) {
|
|
@@ -44,4 +44,17 @@ export function prependEnvelopeToFirstUserText(messages, envelope) {
|
|
|
44
44
|
nextContent[textIdx] = { type: 'text', text: nextText };
|
|
45
45
|
return [{ ...first, content: nextContent }, ...messages.slice(1)];
|
|
46
46
|
}
|
|
47
|
+
/** Keep provenance-bearing guidance separate from the actual participant text. */
|
|
48
|
+
export function prependTurnContextBlocks(messages, blocks, extra) {
|
|
49
|
+
const first = messages[0];
|
|
50
|
+
if (first?.role !== 'user' || !Array.isArray(first.content) || !blocks.length)
|
|
51
|
+
return messages;
|
|
52
|
+
const user = first;
|
|
53
|
+
// Only the first text block carries the ingress presentation. Preserve the
|
|
54
|
+
// other blocks (including provenance) and current media without flattening.
|
|
55
|
+
const content = user.content.map((block, index) => index === 0 && !block.contextRef
|
|
56
|
+
? { ...block, text: userMessageBody({ ...user, content: [block] }, extra) }
|
|
57
|
+
: block);
|
|
58
|
+
return [renderUserMessageForLlm({ ...user, content: [...blocks, ...content] }, extra), ...messages.slice(1)];
|
|
59
|
+
}
|
|
47
60
|
//# sourceMappingURL=turn-user-message.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-user-message.js","sourceRoot":"","sources":["../../src/context/turn-user-message.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"turn-user-message.js","sourceRoot":"","sources":["../../src/context/turn-user-message.ts"],"names":[],"mappings":"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","sourcesContent":["import { type AgentMessageExtra, type AgentMessage, type UserMessage, type TextContentBlock, createUserMessage, userMessagePlainText, userMessageBody, renderUserMessageForLlm } from '@zhin.js/ai';\nimport type { Message } from '@zhin.js/core';\nimport { resolveTurnUserMessage } from '../session/session-io.js';\nimport { prependTurnContextEnvelope } from './turn-envelope.js';\nexport function buildTurnUserMessages(\n commMessage: Message,\n rawContent: string,\n): {\n rawContent: string;\n userMessageExtra?: AgentMessageExtra;\n promptMessages: UserMessage[];\n} {\n const { content, llmMessage } = resolveTurnUserMessage(\n commMessage as import('@zhin.js/core').AgentTurnMessage,\n rawContent,\n );\n return {\n rawContent: content,\n promptMessages: [llmMessage],\n };\n}\n\nexport function applyTurnContextToUserMessages(\n messages: UserMessage[],\n envelope: string | null | undefined,\n): UserMessage[] {\n if (!envelope?.trim() || messages.length === 0) return messages;\n return messages.map((msg, i) => {\n if (i !== 0 || msg.role !== 'user') return msg;\n const text = userMessagePlainText(msg);\n return createUserMessage(\n prependTurnContextEnvelope(text, envelope),\n msg.media,\n msg.timestamp,\n msg.actor,\n msg.cause,\n );\n });\n}\n\nexport function prependEnvelopeToFirstUserText(\n messages: AgentMessage[],\n envelope: string | null | undefined,\n): AgentMessage[] {\n if (!envelope?.trim() || messages.length === 0) return messages;\n const first = messages[0];\n if (!first || first.role !== 'user') return messages;\n\n const content = first.content;\n if (!Array.isArray(content)) return messages;\n\n const textIdx = content.findIndex((b) => b?.type === 'text');\n if (textIdx < 0) {\n return [\n { ...first, content: [{ type: 'text', text: envelope.trim() }, ...content] },\n ...messages.slice(1),\n ];\n }\n\n const block = content[textIdx];\n if (block.type !== 'text') return messages;\n const nextText = prependTurnContextEnvelope(block.text, envelope);\n if (nextText === block.text) return messages;\n\n const nextContent = [...content];\n nextContent[textIdx] = { type: 'text', text: nextText };\n return [{ ...first, content: nextContent }, ...messages.slice(1)];\n}\n\n/** Keep provenance-bearing guidance separate from the actual participant text. */\nexport function prependTurnContextBlocks(messages: AgentMessage[], blocks: readonly TextContentBlock[], extra?: AgentMessageExtra): AgentMessage[] {\n const first = messages[0];\n if (first?.role !== 'user' || !Array.isArray(first.content) || !blocks.length) return messages;\n const user = first as UserMessage;\n // Only the first text block carries the ingress presentation. Preserve the\n // other blocks (including provenance) and current media without flattening.\n const content = user.content.map((block, index) => index === 0 && !block.contextRef\n ? { ...block, text: userMessageBody({ ...user, content: [block] }, extra) }\n : block);\n return [renderUserMessageForLlm({ ...user, content: [...blocks, ...content] }, extra), ...messages.slice(1)];\n}\n"]}
|
|
@@ -52,6 +52,7 @@ export interface AgentLoopTurnInput {
|
|
|
52
52
|
/** Turn-owned deferred selection authority. Required for deferred loading. */
|
|
53
53
|
deferredController?: Readonly<{
|
|
54
54
|
loadedToolNames(): string[];
|
|
55
|
+
modelOutputBlocks?(name: string, args: unknown, text: string): import('@zhin.js/ai').TextContentBlock[] | undefined;
|
|
55
56
|
/** Optional: lets the loop auto-load a deferred tool the model called directly. */
|
|
56
57
|
load?(name: string): Promise<boolean>;
|
|
57
58
|
}>;
|
|
@@ -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 {
|
|
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,
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
494
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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')
|
|
@@ -900,10 +923,14 @@ export async function* runAgentLoopTextTurnRun(input) {
|
|
|
900
923
|
hostReply = !summary.assistant;
|
|
901
924
|
}
|
|
902
925
|
const structuredReply = imReply && !hostReply;
|
|
903
|
-
|
|
926
|
+
// A chat member does not announce how many steps a task took; only non-IM callers get the notice.
|
|
927
|
+
const continuationPrefix = continuations > 0 && input.turnContext.origin.kind !== 'im'
|
|
904
928
|
? `(任务步骤较多,已自动续跑 ${continuations} 次)\n\n` : '';
|
|
905
929
|
const proseReply = structuredReply ? ''
|
|
906
|
-
: sanitizeAssistantReply(rawReply, {
|
|
930
|
+
: sanitizeAssistantReply(rawReply, {
|
|
931
|
+
toolSummary: formatToolCallsForUser(toolCalls),
|
|
932
|
+
...(chatFailure ? { emptyMessage: chatFailureLine('malformed_tool_call', chatFailure) } : {}),
|
|
933
|
+
});
|
|
907
934
|
const textReply = delegatedOnly ? '' : proseReply.trim() ? continuationPrefix + proseReply : proseReply;
|
|
908
935
|
let output = delegatedOnly || structuredReply ? [] : parseOutput(textReply);
|
|
909
936
|
if (!delegatedOnly && structuredReply) {
|
|
@@ -911,26 +938,33 @@ export async function* runAgentLoopTextTurnRun(input) {
|
|
|
911
938
|
output = decodeStructuredReply(rawReply, input.replySegments);
|
|
912
939
|
}
|
|
913
940
|
catch (error) {
|
|
914
|
-
const recovery = await recoverStructuredReply({
|
|
915
|
-
transport: completionUsage.transport, model: llmModel, raw: rawReply,
|
|
916
|
-
error: error instanceof Error ? error : new Error('Invalid structured reply'), signal,
|
|
917
|
-
segments: input.replySegments,
|
|
918
|
-
});
|
|
919
|
-
output = recovery.output;
|
|
920
|
-
// History must match what the user saw: the corrected reply, or the failure text. Never the
|
|
921
|
-
// correction prompt (it embeds the rejected raw text) and never the rejected raw reply.
|
|
922
941
|
const messages = conversationBatches.at(-1)?.messages;
|
|
923
942
|
const rejected = messages?.at(-1);
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
943
|
+
const lenient = decodeLenientStructuredReply(rawReply, input.replySegments);
|
|
944
|
+
if (lenient) {
|
|
945
|
+
output = lenient.output;
|
|
946
|
+
if (messages && rejected?.role === 'assistant') {
|
|
947
|
+
messages[messages.length - 1] = { ...rejected, content: [{ type: 'text', text: lenient.text }] };
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
else {
|
|
951
|
+
const recovery = await recoverStructuredReply({
|
|
952
|
+
transport: completionUsage.transport, model: llmModel, raw: rawReply,
|
|
953
|
+
error: error instanceof Error ? error : new Error('Invalid structured reply'), signal,
|
|
954
|
+
segments: input.replySegments,
|
|
955
|
+
failureText: chatFailureLine('format', { ...chatFailure, random: 0 }),
|
|
956
|
+
});
|
|
957
|
+
output = recovery.output;
|
|
958
|
+
// History must match what the user saw: the corrected reply, or the failure text. Never the
|
|
959
|
+
// correction prompt (it embeds the rejected raw text) and never the rejected raw reply.
|
|
960
|
+
if (messages && rejected?.role === 'assistant') {
|
|
961
|
+
messages[messages.length - 1] = recovery.assistant
|
|
962
|
+
?? { ...rejected, content: [{ type: 'text', text: renderAgentOutput(recovery.output) }] };
|
|
963
|
+
}
|
|
927
964
|
}
|
|
928
965
|
}
|
|
929
966
|
}
|
|
930
967
|
if (!delegatedOnly) {
|
|
931
|
-
if (structuredReply && continuationPrefix && output[0]?.type === 'message') {
|
|
932
|
-
output[0].segments.unshift({ type: 'text', data: { text: continuationPrefix } });
|
|
933
|
-
}
|
|
934
968
|
output = mergeToolOutboundElements(output, toolCalls);
|
|
935
969
|
}
|
|
936
970
|
const finalReply = imReply ? renderAgentOutput(output) : textReply;
|