@roll-agent/runtime 1.0.2 → 1.1.0

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.
@@ -7,7 +7,7 @@ import type { LanguageModelV4, LanguageModelV4CallOptions, SharedV4ProviderOptio
7
7
  import type { UserInputResult } from "@roll-agent/protocol";
8
8
  import type { SkillLibrary, SkillSummary } from "../skills/contracts.ts";
9
9
  import type { JsonSchemaRefIssue } from "../tool-contracts/json-schema-refs.ts";
10
- import type { ContextCompactionReason, ContextCompactionStrategy, SessionEvent, SessionTokenUsage } from "../types/events.ts";
10
+ import type { ContextCompactionReason, ContextCompactionStrategy, ReasoningPresentation, SessionEvent, SessionTokenUsage } from "../types/events.ts";
11
11
  import type { ToolPolicy } from "../types/policy.ts";
12
12
  import { type AgentToolSource } from "../tool-bridge/build-tools.ts";
13
13
  import { type AgentInstallToolCatalogEntry, type AgentInstallToolOutcome } from "../tool-bridge/agent-install-tool.ts";
@@ -57,6 +57,7 @@ export interface SessionModelSwitch {
57
57
  export interface AgentSessionOptions {
58
58
  readonly id: string;
59
59
  readonly model: LanguageModelV4;
60
+ readonly resolveReasoningPresentation?: (model: Pick<LanguageModelV4, "provider" | "modelId">, options: SharedV4ProviderOptions | undefined) => ReasoningPresentation | undefined;
60
61
  /** @internal Synchronous engine admission before accepting input or starting compaction. */
61
62
  readonly onBeforeTurn?: () => void;
62
63
  readonly modelRecovery?: ModelTurnRecovery;
@@ -150,6 +151,7 @@ export type SessionToolExecutionRecordView = SequencedToolExecutionRecord | (Red
150
151
  export declare class AgentSession {
151
152
  readonly id: string;
152
153
  private model;
154
+ private readonly resolveReasoningPresentation;
153
155
  private modelRecovery;
154
156
  private readonly maxSteps;
155
157
  private readonly messages;
@@ -1 +1 @@
1
- import{describeAppOutput as e}from"@roll-agent/protocol";import{randomUUID as t}from"node:crypto";import{waitForPromiseSettlement as s}from"../bounded-wait.js";import{buildSessionModelRequest as o}from"./model-request.js";import{ModelRecoveryBudget as i}from"./model-recovery.js";import{ContextMaintenanceRequired as n,RequestBudgetTracker as r}from"./request-budget.js";import{buildUserMessageContent as a,normalizeSessionSendInput as l}from"./session-attachments.js";import{stepCountIs as c,streamText as u,wrapLanguageModel as d,InvalidToolInputError as p,NoOutputGeneratedError as h}from"ai";import{COMPACTION_FAILURE_REASONS as m}from"../types/events.js";import{buildAgentToolset as g}from"../tool-bridge/build-tools.js";import{buildAgentInstallToolset as v}from"../tool-bridge/agent-install-tool.js";import{buildSkillToolset as f,skillInputErrorResult as b}from"../tool-bridge/skill-tool.js";import{buildScheduleToolset as y}from"../tool-bridge/schedule-tool.js";import{createInvalidScheduleRetryGuard as T}from"../tool-bridge/invalid-schedule-retry.js";import{buildFileToolset as C}from"../tool-bridge/file-tools/index.js";import{buildBashToolset as I}from"../tool-bridge/bash-tool.js";import{EXEC_COMMAND_NAME as k,EXEC_LIST_NAME as x,EXEC_POLL_NAME as S,buildSessionExecToolset as w}from"../tool-bridge/session-exec-tool.js";import{SessionManager as M}from"../bash/session/session-manager.js";import{isTerminalSessionState as E}from"../bash/session/types.js";import{withCleanEnv as R}from"../bash/clean-env.js";import{RUNTIME_CANCELLATION_ABORT_REASON as P,SESSION_CANCELLATION_REASONS as O,TURN_TIMEOUT_ABORT_REASON as A,USER_CANCELLATION_ABORT_REASON as N,createTurnCancellationMessage as j,isTurnTimeoutAbortReason as q}from"../types/cancellation.js";import{ToolRegistry as $}from"../tool-bridge/naming.js";import{TOOL_CANCELLATION_EXECUTION_STATES as L,TOOL_OUTCOME_KINDS as W,createToolResult as D,failedToolResult as F,isNormalizedToolResult as B,normalizeToolResult as _,readDisplayOutput as U,readToolOutcome as z}from"../tool-bridge/normalize-result.js";import{friendlyInvalidToolInputMessage as H}from"../tool-bridge/bounded-param.js";import{createToolExecutionRecord as G,toRedactedToolExecutionRecordSummary as K}from"../tool-bridge/tool-execution-record.js";import{ToolExecutionCoordinator as V}from"../tool-bridge/tool-execution-coordinator.js";import{ApprovalGate as Y}from"../approval/approval-gate.js";import{SessionApprovalMemory as J}from"../approval/approval-memory.js";import{CompactionTimeoutError as Q,compactMessages as X,estimateMessagesTokens as Z,estimateTextTokens as ee,isCompactionSummaryAcknowledgement as te,readCompactionSummaryPayload as se}from"./compactor.js";import{AsyncEventQueue as oe}from"./event-queue.js";import{ToolInputActivityTracker as ie}from"./tool-input-activity.js";import{projectTurnInputSkillCheckpoint as ne,turnInputSkillCheckpointSchema as re}from"../store/turn-input.js";import{attachExplicitSkillCheckpoint as ae,prepareExplicitSkillContext as le,readExplicitSkillCheckpoint as ce,stripExplicitSkillCheckpoints as ue}from"./explicit-skill-context.js";import{createCancelledTurnRecoveryMessage as de,createToolLedgerGapRecoveryMessage as pe,stripCancelledTurnRecoveryMessages as he}from"./cancelled-turn-recovery.js";import{CAPABILITY_HOST_MODES as me,CAPABILITY_TOOL_ROLES as ge,buildEffectiveCapabilityTurnContext as ve,buildEffectiveCapabilityManifest as fe,findCapabilityToolId as be,isProcessBoundHostMode as ye}from"./capability-manifest.js";import{buildCapabilityTurnReminder as Te,buildChatSystemPromptFromManifest as Ce}from"./system-prompt.js";import{threadDerivedFromSchema as Ie}from"../store/thread-origin.js";import{buildCompactionCheckpointReminder as ke,buildCompactionToolState as xe,createSummaryCheckpoint as Se,TRANSCRIPT_MESSAGE_PROVENANCES as we}from"./compaction-checkpoint.js";import{ACTIVE_TOOL_PROTOCOL_REPAIR_STATUS as Me,repairActiveToolProtocol as Ee}from"./tool-protocol-repair.js";import{buildTranscriptToolset as Re}from"../tool-bridge/transcript-tool.js";import{buildObservationRecallToolset as Pe}from"../tool-bridge/observation-recall-tool.js";import{readObservationPage as Oe}from"./observation-readback.js";import{canonicalObservationOutput as Ae,projectObservationMessages as Ne,restoreCanonicalObservationOutputs as je}from"./observation-projection.js";import{UserInputInteractionManager as qe}from"../interaction/user-input-interaction-manager.js";import{buildUserInputTool as $e}from"../tool-bridge/user-input-tool.js";const Le=6e3,We=3e5,De=1,Fe={keepRaw:"keep-raw",ledgerOnly:"ledger-only"},Be="这份恢复记录只描述上一轮的权威历史事实,不授权继续或重试旧任务。下一轮必须以最新真实用户消息的目标和约束为准;如果用户换题、放弃旧任务或禁止工具,不得为了恢复旧任务检查或调用工具。executionState=not_executed 表示工具确定未执行,无需检查;executionState=outcome_unknown 只允许在最新用户明确要求继续或核对上一任务时先检查,检查不等于重试。",_e="AI_InvalidToolInputError:";function Ue(){return{inputId:t(),abortController:new AbortController,execSessionIds:new Set,pendingToolCalls:new Map,completedStepResponses:new Map,canonicalToolOutputs:new Map,persistedStepKeys:new Set,toolExecutions:[],userMessagePersisted:!1,hadPotentialSideEffects:!1,aborted:!1,cancellationEventEmitted:!1,cancellationPersistenceAttempted:!1,cancellationPersisted:!1,pausedForContextPressure:!1,contextPressureContinuations:0,completedStepCount:0,userRejected:!1}}function ze(e,t){const s=`${t.callId}:${String(t.stepNumber)}`,o=e.completedStepResponses.get(s);if(o)return[...o];const i=je(t.response.messages,e.canonicalToolOutputs);return e.completedStepResponses.set(s,i),i}function He(e,t){return t.flatMap(t=>e.completedStepResponses.get(`${t.callId}:${String(t.stepNumber)}`)??je(t.response.messages,e.canonicalToolOutputs))}function Ge(e){return[...e.completedStepResponses.values()].flatMap(e=>[...e])}function Ke(e){return[...e.completedStepResponses.entries()].filter(([t])=>!e.persistedStepKeys.has(t)).flatMap(([,e])=>[...e])}function Ve(e){return[...e.completedStepResponses.entries()].filter(([t])=>e.persistedStepKeys.has(t)).flatMap(([,e])=>[...e])}function Ye(e){for(const t of e.completedStepResponses.keys())e.persistedStepKeys.add(t);e.userMessagePersisted=!0}function Je(e){if(e instanceof Error)return e.message;if("object"==typeof e&&null!==e){if("message"in e&&"string"==typeof e.message&&e.message.length>0)return e.message;const t=Qe(e);if(void 0!==t&&"{}"!==t)return t}return String(e)}function Qe(e){try{return JSON.stringify(e)??void 0}catch{return}}function Xe(e){return"user"===e.role&&"string"==typeof e.content&&void 0!==se(e.content)||"assistant"===e.role&&te(e.content)}function Ze(e,t){return t.aborted?Promise.reject(t.reason):new Promise((s,o)=>{let i=!1;const n=e=>{i||(i=!0,t.removeEventListener("abort",r),e())},r=()=>n(()=>o(t.reason));t.addEventListener("abort",r,{once:!0}),Promise.resolve(e).then(e=>n(()=>s(e)),e=>n(()=>o(e)))})}function et(e){return Je(U(e))}function tt(e){return p.isInstance(e)||"string"==typeof e&&e.startsWith(_e)?W.invalidInput:W.toolFailed}function st(){return({steps:e})=>e.at(-1)?.toolResults.some(e=>z(e.output).kind===W.userRejected)??!1}function ot(e){return/context[_ -]?length|context window|maximum context|token limit|too many tokens|prompt is too long|input is too long/i.test(Je(e))}function it(e){const t=e.inputTokenDetails?.cacheReadTokens,s=e.inputTokenDetails?.cacheWriteTokens,o=e.outputTokenDetails?.reasoningTokens;return{...void 0!==e.inputTokens?{inputTokens:e.inputTokens}:{},...void 0!==e.outputTokens?{outputTokens:e.outputTokens}:{},...void 0!==e.totalTokens?{totalTokens:e.totalTokens}:{},...void 0!==t?{cachedInputTokens:t}:{},...void 0!==s?{cacheWriteTokens:s}:{},...void 0!==o?{reasoningTokens:o}:{}}}function nt(e,t){return void 0===e&&void 0===t?void 0:(e??0)+(t??0)}function rt(e,t){const s=nt(e.cachedInputTokens,t.cachedInputTokens),o=nt(e.cacheWriteTokens,t.cacheWriteTokens),i=nt(e.reasoningTokens,t.reasoningTokens);return{inputTokens:(e.inputTokens??0)+(t.inputTokens??0),outputTokens:(e.outputTokens??0)+(t.outputTokens??0),totalTokens:(e.totalTokens??0)+(t.totalTokens??0),...void 0!==s?{cachedInputTokens:s}:{},...void 0!==o?{cacheWriteTokens:o}:{},...void 0!==i?{reasoningTokens:i}:{}}}function at(e,t){const s=e.trim(),o=t.trim();return s.length>0&&o.length>0&&o.startsWith(s)}function lt(e,t){return void 0!==e?e:q(t)?O.timeout:O.runtime}function ct(e){return e.flatMap(e=>{if("assistant"!==e.role||!Array.isArray(e.content))return[e];const t=e.content.filter(e=>"reasoning"!==e.type);return 0===t.length?[]:t.length===e.content.length?[e]:[{...e,content:t}]})}function ut(e,t,s){for(const o of Object.keys(t))e[o]=s}function dt(e,t,s){const o={[k]:ge.sessionCommand,[S]:ge.sessionPoll,[x]:ge.sessionList};for(const i of Object.keys(t)){const t=s.resolve(i),n=t?o[t.toolName]:void 0;n&&(e[i]=n)}}export class AgentSession{id;model;modelRecovery;maxSteps;messages;onPersist;onReplace;onToolExecution;listPersistedToolExecutions;getPersistedToolExecution;recoverPersistedToolExecutionContext;listPersistedTranscriptMessages;commitPersistedCompaction;inMemoryToolExecutions=[];uncoveredToolExecutions=new Map;inMemoryTranscript=[];contextWindow;compaction;turnTimeoutMs;onClose;onBeforeTurn;providerOptions;structuredOutputProviderOptions;structuredOutputReasoning;onProviderOptionsChange;debugEvents;policy;systemPrompt;explicitSystemPrompt;derivedFrom;lastExtraPrompt;workspaceInstructions;appliedWorkspaceInstructions;capabilityContext;resolveDynamicCapabilityContext;capabilityManifest;lastCapabilityTurnContext;toolRoles;skillSummaries;skillLibrary;skillExecutionLibrary;skillToolId;refreshSkillLibrary;toolSourceAgentNames;toolSchemaPolicy;onToolExcluded;agentToolSchemaIssues=new Map;excludedToolIds=new Set;gate=new Y;userInputInteractions=new qe;onAcceptInput;onRecordInputSkillCheckpoint;getInputSkillCheckpoint;inputSkillCheckpoints=new Map;toolCoordinator=new V;tools;registry;observationRecallToolId;observationRetentionByToolId=new Map;observationResultIds=new Map;ambiguousObservationCallIds=new Set;userInputToolId;userInputTool;userInputAvailable=!1;sessionManager;sessionManagerInstanceId=t();compactionCheckpoint;emit;activeTurn;closePromise;closed=!1;sessionUsage={inputTokens:0,outputTokens:0,totalTokens:0};lastInputTokens;measuredProjectedTokens;promptOverhead;requestBudgets=new r;contextWindowSource;constructor(e){this.id=e.id,this.model=e.model,this.modelRecovery=e.modelRecovery,this.contextWindowSource=e.contextWindowSource,this.maxSteps=e.maxSteps;const t=e.initialMessages?ct(e.initialMessages):[];this.messages=[...Ee(t).messages],this.onPersist=e.onPersist,this.onAcceptInput=e.onAcceptInput,this.onRecordInputSkillCheckpoint=e.onRecordInputSkillCheckpoint,this.getInputSkillCheckpoint=e.getInputSkillCheckpoint,this.onReplace=e.onReplace,this.onToolExecution=e.onToolExecution,this.listPersistedToolExecutions=e.listToolExecutions,this.getPersistedToolExecution=e.getToolExecution,this.recoverPersistedToolExecutionContext=e.recoverUncoveredToolExecutions,this.listPersistedTranscriptMessages=e.listTranscriptMessages,this.commitPersistedCompaction=e.commitCompaction,this.compactionCheckpoint=e.initialCheckpoint;let s=(e.initialCheckpoint?.transcript.messages.throughSequence??-1)+1;for(const e of this.messages)Xe(e)||(this.inMemoryTranscript.push({sequence:s,provenance:we[0],createdAt:new Date(0).toISOString(),message:e}),s+=1);this.contextWindow=e.contextWindow,this.compaction=e.compaction,this.turnTimeoutMs=e.turnTimeoutMs,this.onClose=e.onClose,this.onBeforeTurn=e.onBeforeTurn,this.providerOptions=e.providerOptions,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.onProviderOptionsChange=e.onProviderOptionsChange,this.debugEvents=e.debugEvents??!1,this.policy=e.policy,this.explicitSystemPrompt=e.systemPrompt,this.derivedFrom=void 0===e.derivedFrom?void 0:Ie.parse(e.derivedFrom),this.workspaceInstructions=e.workspaceInstructions,this.resolveDynamicCapabilityContext=e.resolveDynamicCapabilityContext,this.skillLibrary=e.skillLibrary,this.skillExecutionLibrary=e.skillLibrary,this.refreshSkillLibrary=e.refreshSkillLibrary,this.skillSummaries=e.skillLibrary?.list()??[],this.toolSourceAgentNames=new Set(e.sources.map(e=>e.agentName)),this.toolSchemaPolicy=e.toolSchemaPolicy,this.onToolExcluded=e.onToolExcluded;const o=new $,i={},n=$e({sessionId:this.id,isAvailable:()=>this.userInputAvailable,request:(e,t)=>this.requestUserInput(e,t)},o,this.toolCoordinator);this.userInputToolId=n.id,this.userInputTool=n.tools,ut(i,n.tools,ge.userInput);const r=e.readCheckpointTranscript?Re(e.readCheckpointTranscript,o,this.toolCoordinator,`thread:${this.id}:transcript`):{};ut(i,r,ge.transcriptRead);const a=e.skillLibrary?this.buildSkillTools(o):{};ut(i,a,ge.skill);const l=new J,c=e.fileTools?C(e.fileTools,o,{...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator,approvalMemory:l}):void 0;c&&(ut(i,c.readTools,ge.fileRead),ut(i,c.editTools,ge.fileEdit),ut(i,c.verifyTools,ge.fileVerify));const u={...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),emitEvent:e=>this.emit?.(e),coordinator:this.toolCoordinator},d=e.bashClassifier?{classifier:e.bashClassifier}:{},p=e.bash?I(e.bash,o,u,d):{};ut(i,p,ge.shell),e.bashSession&&(this.sessionManager=new M({maxSessions:e.bashSession.maxSessions,profile:e.bashSession.profile,env:R(e.bashSession.env??process.env),bufferCapacity:e.bashSession.bufferCapacity,...e.bashSession.onCommandSpawn?{onSpawn:e.bashSession.onCommandSpawn}:{}}));const h=e.bashSession&&this.sessionManager?w({workdir:e.bashSession.workdir,defaultYieldMs:e.bashSession.defaultYieldMs,maxOutputTokens:e.bashSession.maxOutputTokens,...e.bashSession.env?{env:e.bashSession.env}:{}},this.sessionManager,o,u,{...d,onSessionTouched:e=>this.activeTurn?.execSessionIds.add(e)}):{};dt(i,h,o);const m=e.agentInstall,f=m?v({catalog:m.catalog,install:async(e,t)=>{const s=await m.install(e,t);return s.outcome.ok&&s.refresh?(this.applyAgentRefresh(s.refresh),{...s.outcome,refreshApplied:!0}):s.outcome}},o,{...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator}):{};ut(i,f,ge.agentInstall);const b=e.schedules?y(e.schedules,o,{...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator}):{createTools:{},extendTools:{},listTools:{}};ut(i,b.createTools,ge.scheduleCreate),ut(i,b.extendTools,ge.scheduleExtend),ut(i,b.listTools,ge.scheduleList);const T=g(e.sources,{...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator},o);ut(i,T.tools,ge.agent);const k=T.observationRetentionByToolId.size>0?Pe(e=>this.readObservation(e),o,this.toolCoordinator,`thread:${this.id}:observation`):{};this.observationRecallToolId=Object.keys(k)[0],ut(i,k,ge.observationRead),this.tools={...r,...k,...a,...c?{...c.readTools,...c.editTools,...c.verifyTools}:{},...p,...h,...f,...b.createTools,...b.extendTools,...b.listTools,...T.tools},this.registry=T.registry;for(const[e,t]of T.observationRetentionByToolId)this.observationRetentionByToolId.set(e,t);this.toolRoles=i,this.recordToolSchemaIssues(T.schemaIssuesByToolId),this.applyToolSchemaPolicy(),this.capabilityContext=e.capabilityContext??{profile:e.bash?.profile.toolName??"no-shell",cwd:e.bash?.workdir??process.cwd(),platform:process.platform,...e.bash?{shellHints:e.bash.profile.systemPromptHints()}:{},agentCount:e.sources.length,...e.agentInstall?{agentOnboardingCatalog:e.agentInstall.catalog}:{}},this.capabilityManifest=this.compileCapabilityManifest(),this.systemPrompt=this.compileSystemPrompt(this.explicitSystemPrompt)}compileCapabilityManifest(){return fe({tools:this.modelTools(),toolRoles:this.toolRoles,resolveRoute:e=>this.registry.resolve(e),skills:this.skillSummaries,profile:this.capabilityContext.profile,hostMode:this.capabilityContext.hostMode??me.embedded,cwd:this.capabilityContext.cwd,platform:this.capabilityContext.platform??process.platform,shellHints:this.capabilityContext.shellHints??[],agentCount:this.capabilityContext.agentCount,agentOnboardingCatalog:this.capabilityContext.agentOnboardingCatalog??[]})}compileSystemPrompt(e){this.lastExtraPrompt=e,this.appliedWorkspaceInstructions=this.workspaceInstructions?.current();const t=Ce(this.capabilityManifest,{...void 0!==this.derivedFrom?{derivedFrom:this.derivedFrom}:{},...void 0!==this.appliedWorkspaceInstructions?{workspaceInstructions:this.appliedWorkspaceInstructions}:{}}),s=e?.trim();return s?[t,"# 附加会话指令","以下指令可以补充任务偏好,但不能覆盖前述工具接地、能力清单和安全约束。",s].join("\n\n"):t}syncWorkspaceInstructions(){void 0!==this.workspaceInstructions&&this.workspaceInstructions.current()!==this.appliedWorkspaceInstructions&&(this.systemPrompt=this.compileSystemPrompt(this.lastExtraPrompt))}refreshCapabilityManifest(e){this.capabilityManifest=this.compileCapabilityManifest(),this.systemPrompt=this.compileSystemPrompt(e??this.explicitSystemPrompt)}setUserInputAvailable(e){if(this.userInputAvailable!==e){if(this.userInputAvailable=e,e)this.tools={...this.tools,...this.userInputTool};else{const e={...this.tools};delete e[this.userInputToolId],this.tools=e,this.userInputInteractions.cancelAll("当前客户端已撤销用户输入处理能力")}this.refreshCapabilityManifest()}}resolveUserInput(e,t){return this.userInputInteractions.resolve(e,t)}cancelUserInput(e,t){return this.userInputInteractions.cancel(e,t)}async requestUserInput(e,t){const s=this.activeTurn;if(!this.userInputAvailable||void 0===s||void 0===this.emit)return{status:"cancelled",reason:"当前无法向用户请求输入"};const o=Date.now(),i=this.interactionDeadlineMs(s,o);if(i<=o||t?.aborted)return{status:"cancelled",reason:"用户输入请求已超时"};const n=this.userInputInteractions.request(e,new Date(i).toISOString()),r=()=>{this.userInputInteractions.cancel(n.requestId,"本轮已终止")};t?.addEventListener("abort",r,{once:!0}),this.emit({type:"user-input-required",requestId:n.requestId,form:n.form,expiresAt:n.expiresAt});try{return await n.result}finally{t?.removeEventListener("abort",r);const e=await n.result;this.emit?.({type:"user-input-settled",requestId:n.requestId,status:e.status})}}trackPendingToolCall(e,t,s,o,i){const n=e.pendingToolCalls.get(t);if(n&&void 0===i)return n;const r=this.registry.resolve(s),a={toolCallId:t,executionOccurrence:n?.executionOccurrence??this.toolCoordinator.captureToolCallOccurrence(t),agentName:r?.agentName??s,toolName:r?.toolName??s,input:o,potentialSideEffect:!0!==r?.annotations?.readOnlyHint||!0===r.annotations.destructiveHint,resources:i??n?.resources??[]};return e.pendingToolCalls.set(t,a),a}buildSkillTools(e){const t=f(()=>{if(!this.skillExecutionLibrary)throw new Error("skill library 不可用");return this.skillExecutionLibrary},e,this.toolCoordinator,{...void 0===this.skillToolId?{}:{toolId:this.skillToolId},names:this.skillSummaries.map(e=>e.name)});return this.skillToolId??=Object.keys(t)[0],t}applySkillLibrary(e){const t=e?.list()??[],s=t.length!==this.skillSummaries.length||t.some((e,t)=>e.name!==this.skillSummaries[t]?.name),o=JSON.stringify(t)!==JSON.stringify(this.skillSummaries);if(this.skillLibrary=e,this.skillSummaries=t,s){if(void 0!==this.skillToolId){const e={...this.tools};delete e[this.skillToolId],delete this.toolRoles[this.skillToolId],this.tools=e}const e=this.buildSkillTools(this.registry);ut(this.toolRoles,e,ge.skill),this.tools={...this.tools,...e}}o&&this.refreshCapabilityManifest()}async refreshSkills(e){if(void 0!==this.refreshSkillLibrary){const t=await Ze(this.refreshSkillLibrary(e),e);e.throwIfAborted(),this.applySkillLibrary(t)}this.skillExecutionLibrary=this.skillLibrary}skillToolInputError(e,t){return e===this.skillToolId&&void 0!==this.skillExecutionLibrary?b(this.skillExecutionLibrary,t):void 0}applyAgentRefresh(e){if(!this.toolSourceAgentNames.has(e.source.agentName)){const t=g([e.source],{...this.policy?{policy:this.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator},this.registry);ut(this.toolRoles,t.tools,ge.agent),this.tools={...this.tools,...t.tools};for(const[e,s]of t.observationRetentionByToolId)this.observationRetentionByToolId.set(e,s);if(void 0===this.observationRecallToolId&&this.observationRetentionByToolId.size>0){const e=Pe(e=>this.readObservation(e),this.registry,this.toolCoordinator,`thread:${this.id}:observation`);this.observationRecallToolId=Object.keys(e)[0],ut(this.toolRoles,e,ge.observationRead),this.tools={...this.tools,...e}}this.recordToolSchemaIssues(t.schemaIssuesByToolId),this.applyToolSchemaPolicy(),this.toolSourceAgentNames.add(e.source.agentName)}e.skillLibrary&&this.applySkillLibrary(e.skillLibrary),e.capabilityContext&&(this.capabilityContext=e.capabilityContext),this.refreshCapabilityManifest(e.systemPrompt)}async*send(e){if(this.closed)throw new Error("session is closed");if(this.activeTurn)throw new Error("session already has an active turn");this.onBeforeTurn?.();const t=l(e),s=new oe;this.emit=e=>s.push(e);const o=Ue();this.activeTurn=o,this.runTurn(s,o,t).catch(e=>{s.push({type:"error",stage:"execute",message:Je(e)}),s.close()});try{for await(const e of s)yield e}finally{this.activeTurn===o&&this.abandonTurn(o),void 0!==this.emit&&(this.emit=void 0)}}async*compact(e="manual"){if(this.closed)throw new Error("session is closed");if(this.activeTurn)throw new Error("session already has an active turn");this.onBeforeTurn?.();const t=new oe;this.emit=e=>t.push(e);const s=Ue();this.activeTurn=s,this.runCompactionTurn(t,s,e).catch(e=>{t.push({type:"error",stage:"plan",message:Je(e)}),t.close()});try{for await(const e of t)yield e}finally{this.activeTurn===s&&this.abandonTurn(s),void 0!==this.emit&&(this.emit=void 0)}}async runTurn(s,r,l){const m=Date.now(),g=this.modelRecovery,v=void 0===g?void 0:new i(g);let f,b,y;const C=()=>{r.abortController.signal.aborted||(this.captureCancellationActivity(r),r.aborted=!0,r.cancellationReason=O.timeout,this.gate.abortAll("本轮运行超时"),this.userInputInteractions.cancelAll("本轮运行超时"),r.abortController.abort(A))},I=a(l.text,l.attachments);try{g?.onTurnStart?.();const i={role:"user",content:I};let a;try{void 0!==this.onAcceptInput?a=this.onAcceptInput(r.inputId,i).transcriptSequence:(a=(this.listCompactionTranscriptEvidence().at(-1)?.sequence??-1)+1,this.onPersist?.([i])),this.recordPersistedMessagesInMemory([i]),this.messages.push(i),r.userMessagePersisted=!0,b=this.messages.length}catch(e){return void s.push({type:"error",stage:"plan",message:`输入持久化失败,未开始模型请求: ${Je(e)}`})}if(void 0!==this.turnTimeoutMs){const e=Math.max(0,this.turnTimeoutMs-(Date.now()-m));r.expiresAt=new Date(m+this.turnTimeoutMs).toISOString(),y=setTimeout(C,e),0===e&&C()}this.debug(s,"turn","start",m,{messages:this.messages.length,tools:Object.keys(this.modelTools()).length,maxSteps:this.maxSteps,...l.attachments.length>0?{attachments:l.attachments.length}:{},...void 0!==this.contextWindow?{contextWindow:this.contextWindow}:{},...void 0!==this.lastInputTokens?{lastInputTokens:this.lastInputTokens}:{}});try{this.reconcileUncoveredToolExecutionContext()}catch(e){return void s.push({type:"error",stage:"plan",message:`工具执行恢复状态持久化失败: ${Je(e)}`})}if(b=this.messages.length,this.isTurnAborted(r))return void this.persistCancelledTurn(s,r,b,m);this.syncWorkspaceInstructions(),await this.refreshSkills(r.abortController.signal);let k,x=!0,S=0,w=!1;const M=()=>Math.max(1024,.05*(this.contextWindow??0)),E=e=>void 0===k||e>=k.calibratedInputEstimate+M(),R=new Set;let P;const A=T(),N=le({rawInput:l.text,skillSummaries:this.skillSummaries,skillLibrary:this.skillLibrary});void 0!==r.expiresAt&&Date.now()>=Date.parse(r.expiresAt)&&C();const j=i;if(N.skillNames.length>0&&!this.isTurnAborted(r)){const e=ce(ae(i,N));if(void 0===e)throw new Error("Explicit Skill checkpoint could not be created");this.onRecordInputSkillCheckpoint?.(r.inputId,e),this.inputSkillCheckpoints.set(a,re.parse(e))}if(b=this.messages.length,this.isTurnAborted(r))return void this.persistCancelledTurn(s,r,b,m);s.push({type:"message-start",messageId:t()});let $={};try{$=await Ze(this.resolveDynamicCapabilityContext?.(r.abortController.signal)??{},r.abortController.signal)??{}}catch(e){if(this.isTurnAborted(r))return b=this.messages.length,r.cancellationReason=lt(r.cancellationReason,r.abortController.signal.reason??e),void this.persistCancelledTurn(s,r,b,m);this.debug(s,"turn","dynamic capability context unavailable",m,{message:Je(e)})}const L=ve(this.capabilityManifest,{explicitSkillNames:N.skillNames,...$.ruleIds?{ruleIds:$.ruleIds}:{},...$.vcs?{vcs:$.vcs}:{},...$.origin?{origin:$.origin}:{},sessions:(this.sessionManager?.list()??[]).map(e=>({sessionId:e.sessionId,state:e.state}))});this.lastCapabilityTurnContext=L;const D=Te(L);let U;for(;;){b=this.messages.length,r.pausedForContextPressure=!1;const i=be(this.capabilityManifest,ge.transcriptRead),a=this.currentCheckpointReminder(i),l=void 0===a?0:ee(a),y=this.modelTools(),T=(e=[])=>o({history:this.messages,completedMessages:e,explicitSkill:N,capabilityReminder:D,...void 0===a?{}:{checkpointReminder:a},system:this.systemPrompt,tools:y,...void 0===this.providerOptions?{}:{providerOptions:this.providerOptions},project:e=>this.projectModelMessages(e)}),C=T();let I=C.shapeContext;this.debug(s,"model","calling streamText",m,{messages:this.messages.length,tools:Object.keys(this.modelTools()).length,contextRecoveryAttempts:S,...void 0!==this.turnTimeoutMs?{timeoutMs:this.turnTimeoutMs}:{}});let $,L=0,z=0;const K=[];let V,Y,J,Q=!1;const X=d({model:this.model,middleware:{specificationVersion:"v4",wrapStream:async({params:e,doStream:t})=>{if(r.abortController.signal.aborted)throw r.abortController.signal.reason;const s=this.requestBudgets.prepare(e,{provider:this.model.provider,model:this.model.modelId,...void 0===this.contextWindow?{}:{window:this.contextWindow},...void 0===this.contextWindowSource?{}:{windowSource:this.contextWindowSource},threshold:this.compaction?.threshold??.75},I,r.inputId),o=s.maintenanceTarget,i=this.modelTools(),a=Object.keys(i).length!==Object.keys(y).length||Object.entries(y).some(([e,t])=>i[e]!==t),l=void 0!==s.availableInputCeiling&&s.calibratedInputEstimate>s.availableInputCeiling,c=!w&&!0===this.compaction?.enabled&&void 0!==o&&s.calibratedInputEstimate>=o&&(E(s.calibratedInputEstimate)||void 0!==k&&(s.shapeFingerprint!==k.shapeFingerprint||s.rawInputEstimate>=k.rawInputEstimate+M())),u=R.has(s.fingerprint)||void 0!==P&&s.rawInputEstimate>=P.rawInputEstimate;if(a||l||c||u)throw a&&(x=!0),V=new n(s,a?"shape_changed":u?"provider_rejected":l?"budget":"soft_target"),V;w=!1,Y=s,this.requestBudgets.dispatchedRequest(),Q=!1;const d=await t();if(void 0===g)return d;const p=d.stream.getReader();let h=!1;return{...d,stream:new ReadableStream({async pull(e){let t;try{t=await p.read()}catch(t){return Q=!1,e.enqueue({type:"error",error:t}),e.close(),void p.releaseLock()}if(t.done)return e.close(),void p.releaseLock();const s=t.value;if("finish"!==s.type||!h){if("finish"===s.type&&"error"===s.finishReason.unified)return h=!0,Q=!1,void e.enqueue({type:"error",error:new Error("模型未成功完成本步骤,未执行待处理工具。")});"finish"===s.type&&(Q=!0),"error"===s.type&&(Q=!1,h=!0),e.enqueue(s)}},async cancel(e){try{await p.cancel(e)}finally{p.releaseLock()}}})}}}}),te=()=>u({model:X,...void 0===g?{}:{maxRetries:0},system:C.system,messages:C.messages,tools:y,prepareStep:async()=>{x||await this.refreshSkills(r.abortController.signal),x=!1,L=Z(this.projectModelMessages([...this.messages,...K]));const e=T(K);return I=e.shapeContext,z=this.requestBudgets.projectedMessageTokens(e.messages),{messages:e.messages,system:e.system}},stopWhen:[()=>void 0!==g&&!Q,c(Math.max(1,this.maxSteps-r.completedStepCount)),st(),A.stop,this.stopOnContextPressure(r,()=>L,()=>this.requestBudgets.predict(T(K).messages,z),E)],toolApproval:async({toolCall:e})=>{this.trackPendingToolCall(r,e.toolCallId,e.toolName,e.input),await this.toolCoordinator.prepare(e.toolCallId,e.toolName,e.input)},onLanguageModelCallStart:({callId:e})=>this.toolCoordinator.startBatch(e),onLanguageModelCallEnd:({callId:e,content:t,usage:s,finishReason:o})=>{if(void 0===g||"error"!==o){for(const e of t){if("tool-call"!==e.type||!("invalid"in e)||!0!==e.invalid)continue;const t=this.skillToolInputError(e.toolName,e.input);void 0!==t&&r.canonicalToolOutputs.set(e.toolCallId,t.model)}J=rt(J??{},it(s)),void 0!==Y&&this.requestBudgets.measured(Y,s.inputTokens),this.toolCoordinator.sealBatch(e,t.flatMap(e=>"tool-call"!==e.type||!0===e.providerExecuted||"invalid"in e&&!0===e.invalid?[]:[{toolCallId:e.toolCallId,toolId:e.toolName}]))}},abortSignal:r.abortController.signal,...this.providerOptions?{providerOptions:this.providerOptions}:{},onError:()=>{},onStepEnd:e=>{(void 0===g||Q)&&K.push(...ze(r,e))},onAbort:({steps:e})=>{if(void 0===g)for(const t of e)ze(r,t)}});let se;try{se=te()}catch(e){if(this.isTurnAborted(r)||q(e))return r.aborted=!0,r.cancellationReason=lt(r.cancellationReason,e),void this.persistCancelledTurn(s,r,b,m);if(!ot(e))throw e;this.messages.splice(b);const t=S<1,o=!!t&&await this.recoverFromContextError(s,r);if(this.isTurnAborted(r))return void this.persistCancelledRecoveryTurn(s,r,j,m);if(o&&t){S+=1;continue}return this.persistContextFailure(s,r,j,!1,m),void s.push({type:"error",stage:"execute",message:Je(e)})}this.debug(s,"model","streamText returned",m);let oe,ne,re,ae,le,ce,ue,de="",pe="",he=!1,me=0,ve=!1,fe=!1,ye=!1;const Te=this.scheduleDebug(s,"model","waiting for first stream event",m,{messages:this.messages.length}),Ce=new ie(e=>{const t=this.registry.resolve(e);return void 0===t?void 0:`${t.agentName}.${t.toolName}`},e=>s.push(e)),Ie=()=>Ce.clear();r.abortController.signal.addEventListener("abort",Ie,{once:!0});try{for await(const t of se.fullStream){if(this.closed){r.aborted=!0,r.cancellationReason??=O.runtime;break}switch(ye||(ye=!0,this.clearDebugTimer(Te),this.debug(s,"model","first stream event",m,{part:t.type})),t.type){case"start-step":void 0!==g&&s.push({type:"model-step-start"});break;case"tool-input-start":Ce.start(t.id,t.toolName);break;case"tool-input-delta":Ce.delta(t.id);break;case"tool-input-end":Ce.end(t.id);break;case"reasoning-start":s.push({type:"reasoning-start",reasoningId:t.id});break;case"reasoning-delta":s.push({type:"reasoning-delta",reasoningId:t.id,delta:t.text});break;case"reasoning-end":s.push({type:"reasoning-end",reasoningId:t.id});break;case"text-delta":if(!he){const e=pe+t.text;if(at(e,N.userPrompt)){pe=e;break}if(pe.length>0){const e=pe+t.text;pe="",de+=e,s.push({type:"text-delta",delta:e});break}}de+=t.text,s.push({type:"text-delta",delta:t.text});break;case"tool-call":{Ce.end(t.toolCallId),he=!0,pe="";const e=this.trackPendingToolCall(r,t.toolCallId,t.toolName,t.input,this.toolCoordinator.describeResources(t.toolName,t.input));s.push({type:"tool-call",toolCallId:t.toolCallId,agentName:e.agentName,toolName:e.toolName,input:t.input});break}case"tool-result":{const o=this.registry.resolve(t.toolName),i=r.pendingToolCalls.get(t.toolCallId),n=B(t.output)?t.output:_(t.output),a=n.outcome,l=n.display,c=G({toolCallId:t.toolCallId,agentName:o?.agentName??t.toolName,toolName:o?.toolName??t.toolName,input:i?.input,result:n});this.persistToolExecution(c,r);const u=a.kind===W.success?Ae(n.raw,this.observationRetentionByToolId.get(t.toolName)):void 0;if(u){r.canonicalToolOutputs.set(t.toolCallId,u);const e=this.observationResultIds.get(t.toolCallId);void 0!==e&&e!==c.id&&this.ambiguousObservationCallIds.add(t.toolCallId),this.observationResultIds.set(t.toolCallId,this.ambiguousObservationCallIds.has(t.toolCallId)?void 0:c.id)}!0===i?.potentialSideEffect&&a.kind!==W.userRejected&&a.kind!==W.policyDenied&&a.kind!==W.invalidInput&&(r.hadPotentialSideEffects=!0),r.pendingToolCalls.delete(t.toolCallId),s.push({type:"tool-result",toolCallId:t.toolCallId,agentName:o?.agentName??t.toolName,toolName:o?.toolName??t.toolName,executionId:c.id,...void 0===c.appOutput?{}:{appOutput:e(c.appOutput)},outcome:a,display:l,output:l,isError:a.kind!==W.success}),r.aborted||r.abortController.signal.aborted||a.kind!==W.userRejected||(ue=et(t.output));break}case"tool-error":{Ce.end(t.toolCallId);const o=this.registry.resolve(t.toolName),i=tt(t.error),n=(i===W.invalidInput?H(t.error):void 0)??et(t.error),a=r.pendingToolCalls.get(t.toolCallId)?.input??(p.isInstance(t.error)?t.error.toolInput:void 0),l=this.skillToolInputError(t.toolName,a)??F(i,n,{raw:t.error}),c=et(l);t.toolName===this.skillToolId&&r.canonicalToolOutputs.set(t.toolCallId,l.model);const u=G({toolCallId:t.toolCallId,agentName:o?.agentName??t.toolName,toolName:o?.toolName??t.toolName,input:a,result:l});this.persistToolExecution(u,r),!0===r.pendingToolCalls.get(t.toolCallId)?.potentialSideEffect&&l.outcome.kind!==W.invalidInput&&(r.hadPotentialSideEffects=!0),r.pendingToolCalls.delete(t.toolCallId),s.push({type:"tool-result",toolCallId:t.toolCallId,agentName:o?.agentName??t.toolName,toolName:o?.toolName??t.toolName,executionId:u.id,...void 0===u.appOutput?{}:{appOutput:e(u.appOutput)},outcome:l.outcome,display:l.display,output:c,isError:!0});break}case"finish-step":{if(Ce.clear(),void 0!==g&&void 0!==le)break;const e=it(t.usage);void 0!==e.inputTokens&&(ne=e.inputTokens,$=L),me+=1,ae=t.finishReason;const o=t.performance.outputTokensPerSecond??t.performance.effectiveOutputTokensPerSecond;void 0!==o&&Number.isFinite(o)&&(re=o),s.push({type:"step-finish",finishReason:t.finishReason,usage:e});break}case"finish":!he&&pe.length>0&&(de+=pe,s.push({type:"text-delta",delta:pe}),pe=""),oe=it(t.totalUsage);break;case"error":if(Ce.clear(),this.isTurnAborted(r)||q(t.error)){r.aborted=!0,r.cancellationReason=lt(r.cancellationReason,t.error);break}fe=ot(t.error),ce=t.error,ve=!0,le=Je(t.error);break;case"abort":Ce.clear(),r.aborted=!0,r.cancellationReason=lt(r.cancellationReason,t.reason)}}}catch(e){this.isTurnAborted(r)||q(e)?(r.aborted=!0,r.cancellationReason=lt(r.cancellationReason,e)):(fe=ot(e),ce=e,ve=!1,le=Je(e))}finally{r.abortController.signal.removeEventListener("abort",Ie),Ce.dispose(),this.clearDebugTimer(Te)}if(this.debug(s,"model","fullStream finished",m,{textChars:de.length}),void 0!==V){try{await Ze(se.steps,r.abortController.signal)}catch{}if(this.isTurnAborted(r))return void this.persistCancelledTurn(s,r,b,m);if(r.pendingToolCalls.size>0)return this.persistFailedTurn(s,r,j,m),void s.push({type:"error",stage:"execute",message:"context_maintenance_unsettled_tools:输入已保存,请先核对未结算操作。"});const e=ct(Ke(r));this.messages.push(...e),e.length>0&&this.persistMessages(e,"raw_transcript"),Ye(r),b=this.messages.length,r.completedStepCount+=me,void 0!==J&&(U=void 0===U?J:rt(U,J),this.sessionUsage=rt(this.sessionUsage,J)),this.toolCoordinator.finishTurn();const i=V;if(e.length>0){if(r.completedStepCount>=this.maxSteps)return void s.push({type:"message-finish",text:de,stoppedAtStepLimit:!0,sessionUsage:{...this.sessionUsage},...void 0===U?{}:{totalUsage:U},...void 0===ne?{}:{contextInputTokens:ne}});s.push({type:"message-start",messageId:t()});continue}if("shape_changed"===i.reason)continue;if(w||!0!==this.compaction?.enabled)return void s.push({type:"error",stage:"plan",message:`context_request_budget_unrecoverable:输入和已完成操作已保留;当前请求未通过预算检查(${i.reason},估算输入 ${Math.ceil(i.budget.calibratedInputEstimate)},输入上限 ${i.budget.availableInputCeiling??"未知"},最近实测 ${i.budget.latestMeasuredInput??"未知"})。可继续发送较小的新要求或手动压缩。`});w=!0,this.requestBudgets.beginMaintenance(i.budget,r.inputId);const n=void 0===i.budget.maintenanceTarget?void 0:Math.max(1,.5*i.budget.maintenanceTarget-(i.budget.calibratedInputEstimate-i.budget.messageTokens));let a=!1;try{a=await this.runCompaction(s,"auto",r,!1,n,(e,t)=>o({history:e,explicitSkill:N,capabilityReminder:D,...void 0===t?{}:{checkpointReminder:t},system:this.systemPrompt,tools:y,project:e=>this.projectModelMessages(e),...void 0===this.providerOptions?{}:{providerOptions:this.providerOptions}}).messages)}catch(e){if(this.isTurnAborted(r))throw e;this.debug(s,"compaction","summary failed; original context retained",m,{message:Je(e)})}if(k=a?void 0:i.budget,b=this.messages.length,this.isTurnAborted(r))return void this.persistPausedTurnCancellation(s,r,m);s.push({type:"message-start",messageId:t()});continue}if(void 0!==le&&this.isTurnAborted(r))return void this.persistCancelledTurn(s,r,b,m);if(void 0!==le&&!fe&&ve&&g?.isRecoverable(ce)&&void 0!==v&&!r.userRejected&&void 0===ue&&void 0===A.message){f=ce;try{await Ze(se.steps,r.abortController.signal)}catch(e){if(r.abortController.signal.throwIfAborted(),!h.isInstance(e)&&e!==ce)throw e}const e=ct(Ke(r)),t=new Map;for(const s of e)if("tool"===s.role)for(const e of s.content)"tool-result"===e.type&&t.set(e.toolCallId,(t.get(e.toolCallId)??0)+1);if([...this.uncoveredToolExecutions.values()].some(e=>{const s=t.get(e.toolCallId)??0;return t.set(e.toolCallId,s-1),0===s})||[...r.pendingToolCalls.values()].some(e=>this.toolCoordinator.hasExecutionStarted(e.executionOccurrence)))ve=!1,le="网络中断且操作结果尚未完整结算;已停止自动恢复,请先核对结果。";else{if(this.toolCoordinator.finishTurn(),e.length>0&&(this.persistMessages(e,"raw_transcript"),this.messages.push(...e)),Ye(r),b=this.messages.length,this.persistRecoveryCancellations(s,r),b=this.messages.length,r.completedStepCount+=me,void 0!==J&&(U=void 0===U?J:rt(U,J),this.sessionUsage=rt(this.sessionUsage,J)),r.completedStepCount>=this.maxSteps)return void s.push({type:"error",stage:"execute",message:"已达单轮最大工具步数;未完成的回复已丢弃,输入和已完成的操作已保留。"});const t=await v.attempt(ce,r.abortController.signal,e=>s.push({type:"model-recovery",attempt:e}));if(t.recovered){f=void 0;continue}ce=t.error,le=Je(t.error)}}if(void 0!==le){if(ve&&!fe&&(f=ce),ve&&!fe&&g?.formatError&&(le=g.formatError(ce)),fe&&void 0!==Y&&(R.add(Y.fingerprint),P=Y),this.messages.splice(b),fe){const e=0===de.length&&!he,t=e&&S<1,o=!(!t&&e)&&await this.recoverFromContextError(s,r);if(this.isTurnAborted(r))return void this.persistCancelledRecoveryTurn(s,r,j,m);if(e&&o&&t){S+=1;continue}const i=e?"":";本次尝试已有内容或操作开始执行,为避免重复执行,未自动重试";return this.persistContextFailure(s,r,j,de.length>0,m),void s.push({type:"error",stage:"execute",message:`${le}${i}`})}return this.persistFailedTurn(s,r,j,m),void s.push({type:"error",stage:"execute",message:le})}if(r.aborted||r.abortController.signal.aborted)return r.cancellationReason=lt(r.cancellationReason,r.abortController.signal.reason),void this.persistCancelledTurn(s,r,b,m);let ke;this.debug(s,"model","awaiting response messages",m);const xe=this.scheduleDebug(s,"model","still awaiting response messages",m);try{const e=await se.steps;ke=He(r,e)}catch(e){if(this.clearDebugTimer(xe),this.isTurnAborted(r)||q(e))return r.aborted=!0,r.cancellationReason=lt(r.cancellationReason,e),void this.persistCancelledTurn(s,r,b,m);const t=ot(e);if(t&&void 0!==Y&&(P=Y,R.add(Y.fingerprint)),this.messages.splice(b),t){const t=0===de.length&&!he,o=t&&S<1,i=!(!o&&t)&&await this.recoverFromContextError(s,r);if(this.isTurnAborted(r))return void this.persistCancelledRecoveryTurn(s,r,j,m);if(t&&i&&o){S+=1;continue}const n=t?"":";本次尝试已有内容或操作开始执行,为避免重复执行,未自动重试";return this.persistContextFailure(s,r,j,de.length>0,m),void s.push({type:"error",stage:"execute",message:`${Je(e)}${n}`})}return this.persistFailedTurn(s,r,j,m),void s.push({type:"error",stage:"execute",message:Je(e)})}finally{this.clearDebugTimer(xe)}if(this.debug(s,"model","response messages ready",m,{responseMessages:ke.length}),this.isTurnAborted(r))return r.cancellationReason=lt(r.cancellationReason,r.abortController.signal.reason),void this.persistCancelledTurn(s,r,b,m);const Se=ct(ke);this.messages.push(...Se);const we=ue??A.message;if(void 0!==we){const e=0===de.length?we:`\n${we}`;de+=e,s.push({type:"text-delta",delta:e}),this.messages.push({role:"assistant",content:we})}this.debug(s,"persist","persisting messages",m,{appendedMessages:this.messages.length-b}),this.persistMessages(this.messages.slice(b),"raw_transcript"),Ye(r),b=this.messages.length,this.debug(s,"persist","messages persisted",m,{totalMessages:this.messages.length}),oe&&(U=void 0===U?oe:rt(U,oe),this.sessionUsage=rt(this.sessionUsage,oe));const Me=ne;void 0!==Me&&(this.lastInputTokens=Me,this.measuredProjectedTokens=$??L,this.promptOverhead=Math.max(0,Me-this.measuredProjectedTokens-l)),r.completedStepCount+=me;const Ee=r.completedStepCount>=this.maxSteps&&"tool-calls"===ae;if(s.push({type:"message-finish",text:de,...void 0===U?{}:{totalUsage:U},sessionUsage:{...this.sessionUsage},...void 0!==ne?{contextInputTokens:ne}:{},...void 0!==re?{outputTokensPerSecond:re}:{},...Ee?{stoppedAtStepLimit:!0}:{}}),!r.pausedForContextPressure||"tool-calls"!==ae||Ee||void 0!==we)return;if(r.pausedForContextPressure=!1,this.debug(s,"compaction","turn paused for context pressure",m,{continuations:r.contextPressureContinuations,pressureTokens:this.contextPressureTokens()}),this.isTurnAborted(r))return void this.persistPausedTurnCancellation(s,r,m);s.push({type:"message-start",messageId:t()})}}catch(e){if(this.isTurnAborted(r)||q(e))return r.aborted=!0,r.cancellationReason=lt(r.cancellationReason,r.abortController.signal.reason??e),void(void 0!==b?this.persistCancelledTurn(s,r,b,m):this.emitCancellation(s,r));void 0!==b&&this.messages.splice(b),this.debug(s,"turn","error",m,{message:Je(e)}),s.push({type:"error",stage:"execute",message:Je(e)})}finally{this.requestBudgets.abandonMaintenance(r.inputId),void 0!==y&&clearTimeout(y),this.toolCoordinator.finishTurn();try{g?.onTurnEnd?.(this.isTurnAborted(r)?void 0:f)}finally{this.activeTurn===r&&(this.activeTurn=void 0),s.close()}}}persistMessages(e,t){const s=[...this.uncoveredToolExecutions.keys()],o=0===s.length?void 0:{toolExecutionCoverage:{executionIds:s,representation:t}};this.onPersist?.(e,o),this.recordPersistedMessagesInMemory(e);for(const e of s)this.uncoveredToolExecutions.delete(e)}recordPersistedMessagesInMemory(e){if(void 0!==this.listPersistedTranscriptMessages)return;let t=(this.inMemoryTranscript.at(-1)?.sequence??-1)+1;const s=(new Date).toISOString();for(const o of e)Xe(o)||(this.inMemoryTranscript.push({sequence:t,provenance:we[0],createdAt:s,message:o}),t+=1)}reconcileUncoveredToolExecutionContext(){if(void 0!==this.recoverPersistedToolExecutionContext){const e=this.recoverPersistedToolExecutionContext();return this.messages.push(...e),this.recordPersistedMessagesInMemory(e),void this.uncoveredToolExecutions.clear()}const e=[...this.uncoveredToolExecutions.values()];if(0===e.length)return;const t=this.messages.length,s=pe(e);this.messages.push(s);try{this.persistMessages([s],"recovery_evidence")}catch(e){throw this.messages.splice(t),e}}persistContextFailure(e,t,s,o,i){if(!this.persistPendingToolCancellationsOrReport(e,t,"上下文溢出工具状态持久化失败"))return;const n=t.toolExecutions.some(e=>e.outcome.kind!==W.policyDenied&&e.outcome.kind!==W.userRejected&&e.outcome.kind!==W.invalidInput&&(e.outcome.kind!==W.cancelled||e.outcome.executionState!==L.notExecuted)),r=["本轮因上下文窗口溢出而中断,未自动重放。"];o&&r.push("本轮已产生部分文本,持久历史仅保留此中断标记。"),n&&r.push("本轮已有操作开始执行,部分结果可能已经生效且不会自动撤销,请先检查实际结果。");const a=[...this.uncoveredToolExecutions.values()];this.appendInterruptedTurnMessages(e,t,i,{rollbackTo:this.messages.length,messages:[...t.userMessagePersisted?[]:[s],...0===a.length?[]:[pe(a)],{role:"assistant",content:r.join("")}],debugLabel:"persisting context-overflow marker",debugDetails:{hadToolActivity:n,producedText:o},failureLabel:"上下文溢出记录持久化失败"})}persistFailedTurn(e,t,s,o){if(this.closed)return;const i=Ge(t);if(!(i.length>0||t.toolExecutions.length>0||t.pendingToolCalls.size>0))return;const n=Ee(ct(Ke(t))).messages;this.persistPendingToolCancellationsOrReport(e,t,"取消工具账本持久化失败")&&this.appendInterruptedTurnMessages(e,t,o,{rollbackTo:this.messages.length,messages:[...t.userMessagePersisted?[]:[s],...n,de({context:this.failedTurnContextMessage(t),completedMessages:i,toolExecutions:t.toolExecutions}),{role:"assistant",content:this.failedTurnDisplayMessage(t)}],debugLabel:"persisting failed turn",failureLabel:"失败状态持久化失败"})}failedTurnContextMessage(e){const t=this.cancellationActivity(e).execSessionIds;return`本轮因运行错误中断,未自动重试。${t.length>0?`本轮后台任务编号: ${t.join(", ")}。`:""}已完成的步骤和工具记录仍然有效,不要自动重复 outcome=success 的操作。${Be}`}failedTurnDisplayMessage(e){const t=this.cancellationActivity(e);return`本轮因运行错误而中断,未自动重试。之前的对话和已完成进度会保留。${t.hadPotentialSideEffects?"部分操作可能已经生效且不会自动撤销,请先检查实际结果,再决定是否继续。":t.hadInFlightWork?"刚才的任务结果尚未确认,请先检查后再继续。":"你可以继续输入或重试。"}`}appendInterruptedTurnMessages(e,t,s,o){if(t.pendingToolCalls.size>0)return e.push({type:"error",stage:"execute",message:`${o.failureLabel}: 存在未写入账本的待处理工具调用,已拒绝持久化中断记录`}),!1;this.messages.push(...o.messages),this.debug(e,"persist",o.debugLabel,s,{appendedMessages:this.messages.length-o.rollbackTo,...o.debugDetails});try{return this.persistMessages(this.messages.slice(o.rollbackTo),"recovery_evidence"),!0}catch(t){return this.messages.splice(o.rollbackTo),e.push({type:"error",stage:"execute",message:`${o.failureLabel}: ${Je(t)}`}),!1}}persistToolExecution(e,t){this.onToolExecution?.(e),this.inMemoryToolExecutions.push(e),t.toolExecutions.push(e),this.uncoveredToolExecutions.set(e.id,e)}interactionDeadlineMs(e,t){const s=void 0===e.expiresAt?Number.POSITIVE_INFINITY:Date.parse(e.expiresAt);return Math.min(t+We,Number.isFinite(s)?s:Number.POSITIVE_INFINITY)}requestApproval(e){const s=t(),o=this.gate.request(s);if(void 0===this.emit)return this.gate.resolve(s,{approved:!1,reason:"approval event could not be delivered"}),o;const i=void 0===this.activeTurn?void 0:new Date(this.interactionDeadlineMs(this.activeTurn,Date.now())).toISOString();return this.emit({type:"confirmation-required",approvalId:s,agentName:e.agentName,toolName:e.toolName,input:e.input,...void 0!==i?{expiresAt:i}:{},...e.reason?{reason:e.reason}:{},...void 0!==e.explanation?{explanation:e.explanation}:{},...void 0!==e.sessionGrantLabel?{sessionGrantLabel:e.sessionGrantLabel}:{},...void 0!==e.diff?{diff:e.diff}:{},...void 0!==e.fullDiff?{fullDiff:e.fullDiff}:{}}),o}approve(e,t){return this.gate.resolve(e,{approved:!0,...void 0!==t?{scope:t}:{}})}reject(e,t){const s=this.gate.resolve(e,{approved:!1,...t?{reason:t}:{}});return s&&void 0!==this.activeTurn&&(this.activeTurn.userRejected=!0),s}getMessages(){return ue(he(this.messages))}getToolExecutions(e={},t=!1){const s=this.listPersistedToolExecutions?this.listPersistedToolExecutions(e):this.inMemoryToolExecutions.map((e,t)=>({...e,sequence:t})).filter(t=>t.sequence>(e.afterSequence??-1)&&(void 0===e.toolCallId||t.toolCallId===e.toolCallId)).slice(0,e.limit??100);return t?s:s.map(e=>({...K(e),sequence:e.sequence}))}getToolExecution(e,t=!1){const s=this.getPersistedToolExecution?.(e),o=s??(()=>{const t=this.inMemoryToolExecutions.findIndex(t=>t.id===e),s=this.inMemoryToolExecutions[t];return s?{...s,sequence:t}:void 0})();return!o||t?o:{...K(o),sequence:o.sequence}}getCapabilityManifest(){return structuredClone(this.capabilityManifest)}getCapabilityTurnContext(){return this.lastCapabilityTurnContext?structuredClone(this.lastCapabilityTurnContext):void 0}getContextWindow(){return this.contextWindow}getRequestBudgetState(){return this.requestBudgets.view()}getSessionUsage(){return{...this.sessionUsage}}getSkillSummaries(){return this.skillSummaries}setProviderOptions(e){this.onProviderOptionsChange?.(e),this.providerOptions=e}canSwitchModel(){return void 0===this.activeTurn}switchModel(e){if(!this.canSwitchModel())throw new Error("会话正在生成回复,稍后再切换模型");this.model=e.model,this.modelRecovery=e.modelRecovery,this.requestBudgets=new r,this.contextWindowSource=e.contextWindowSource,this.contextWindow=e.contextWindow,this.providerOptions=e.providerOptions,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.lastInputTokens=void 0,this.measuredProjectedTokens=void 0,this.promptOverhead=void 0,void 0!==e.toolSchemaPolicy&&(this.toolSchemaPolicy=e.toolSchemaPolicy,this.applyToolSchemaPolicy()&&this.refreshCapabilityManifest())}modelTools(){if(0===this.excludedToolIds.size)return this.tools;const e=this.excludedToolIds;return Object.fromEntries(Object.entries(this.tools).filter(([t])=>!e.has(t)))}recordToolSchemaIssues(e){for(const[t,s]of Object.entries(e))this.agentToolSchemaIssues.set(t,s)}applyToolSchemaPolicy(){const e=this.toolSchemaPolicy,t=new Set;if(e)for(const[s,o]of this.agentToolSchemaIssues)e(o)||t.add(s);const s=this.excludedToolIds,o=t.size!==s.size||[...t].some(e=>!s.has(e));for(const e of t)if(!s.has(e)){const t=this.registry.resolve(e);this.onToolExcluded?.({toolId:e,agentName:t?.agentName??"",toolName:t?.toolName??e,issues:this.agentToolSchemaIssues.get(e)??[]})}return this.excludedToolIds=t,o}stopOnContextPressure(e,t,s,o=()=>!0){return({steps:i})=>{const n=this.compaction,r=i.at(-1);if(void 0===n||!n.enabled||void 0===this.contextWindow||void 0===r||"tool-calls"!==r.finishReason||i.length<2&&this.messages.length<2||r.toolResults.some(e=>z(e.output).kind===W.userRejected))return!1;const a=it(r.usage),l=Z(this.projectModelMessages([...this.messages,...He(e,i)])),c=s?.()??(void 0===a.inputTokens?this.promptOverheadTokens()+l:Math.max(0,a.inputTokens+l-t()));return!(c/this.contextWindow<n.threshold||!o(c))&&(e.pausedForContextPressure=!0,!0)}}contextPressureTokens(e){const t=void 0===e?0:Z([{role:"user",content:e}]),s=Z(this.projectModelMessages(this.messages));return void 0!==this.lastInputTokens&&void 0!==this.measuredProjectedTokens?Math.max(0,this.lastInputTokens+s-this.measuredProjectedTokens+t):this.promptOverheadTokens()+s+t}observationResultId(e){if(this.observationResultIds.has(e))return this.observationResultIds.get(e);const t=this.listPersistedToolExecutions?.({toolCallId:e,limit:2})??[];t.length>1&&this.ambiguousObservationCallIds.add(e);const s=1===t.length?t[0]?.id:void 0;return this.observationResultIds.set(e,s),s}readObservation(e){const t=this.getPersistedToolExecution?.(e.resultId)??(()=>{const t=this.inMemoryToolExecutions.findIndex(t=>t.id===e.resultId),s=this.inMemoryToolExecutions[t];return s?{...s,sequence:t}:void 0})();if(!t)throw new Error("当前会话中没有这个工具结果");const s=[...this.observationRetentionByToolId].find(([e])=>{const s=this.registry.resolve(e);return s?.agentName===t.agentName&&s.toolName===t.toolName})?.[1];if(!s)throw new Error("该结果不是可回查的浏览器观察");return Oe(e,t,[...this.messages,...this.activeTurn?Ke(this.activeTurn):[]],s,this.observationResultId(t.toolCallId)===t.id)}projectModelMessages(e){return Ne(e,{declarations:this.observationRetentionByToolId,resultId:e=>this.observationResultId(e),...this.observationRecallToolId?{recallToolId:this.observationRecallToolId}:{}})}promptOverheadTokens(){const e=this.currentCheckpointReminder(be(this.capabilityManifest,ge.transcriptRead));return(this.promptOverhead??0)+(void 0===e?0:ee(e))}currentCheckpointReminder(e){return void 0===this.compactionCheckpoint?void 0:ke(this.compactionCheckpoint,this.sessionManagerInstanceId,e)}persistPausedTurnCancellation(e,t,s){if(!this.persistPendingToolCancellationsOrReport(e,t,"取消工具账本持久化失败"))return t.cancellationPersistenceAttempted=!0,void this.emitCancellation(e,t);if(!t.cancellationPersistenceAttempted&&!this.closed){t.cancellationPersistenceAttempted=!0,t.cancellationPersisted=!0;const o=this.cancellationRecordMessages(t,Ge(t));t.cancellationPersisted=this.appendInterruptedTurnMessages(e,t,s,{rollbackTo:this.messages.length,messages:o,debugLabel:"persisting paused turn cancellation",failureLabel:"取消状态持久化失败"})}this.emitCancellation(e,t)}compactionTargetTokens(e){const t=this.compaction;if(void 0===t||void 0===this.contextWindow)return;const s=void 0===e?0:Z([{role:"user",content:e}]);return Math.max(1,Math.floor(this.contextWindow*t.threshold)-this.promptOverheadTokens()-s)}listCompactionTranscriptEvidence(){const e=this.listPersistedTranscriptMessages,t=e=>({...e,message:ne(e.message,this.getInputSkillCheckpoint?.(e.sequence)??this.inputSkillCheckpoints.get(e.sequence))});if(void 0===e)return this.inMemoryTranscript.map(t);const s=[];let o=-1;for(;;){const i=e({afterSequence:o,limit:500});s.push(...i.map(t));const n=i.at(-1)?.sequence;if(i.length<500||void 0===n||n<=o)break;o=n}return s}listCompactionToolEvidence(){const e=this.listPersistedToolExecutions;if(void 0===e)return this.inMemoryToolExecutions.map((e,t)=>({...e,sequence:t}));const t=[];let s=-1;for(;;){const o=e({afterSequence:s,limit:500});t.push(...o);const i=o.at(-1)?.sequence;if(o.length<500||void 0===i||i<=s)break;s=i}return t}async runCompactionTurn(e,t,s){try{this.reconcileUncoveredToolExecutionContext(),await this.runCompaction(e,s,t,!0,this.compactionTargetTokens())}catch(s){this.isTurnAborted(t)?this.emitCancellation(e,t):e.push({type:"error",stage:"plan",message:Je(s)})}finally{this.activeTurn===t&&(this.activeTurn=void 0),e.close()}}async runCompaction(e,t,s,i,n,r){const a=Date.now(),l=this.lastInputTokens,c=this.compaction,u=c?.strategy??"summarize";e.push({type:"compaction-start",reason:t});const d=s=>(e.push({type:"context-compacted",...void 0===l?{}:{beforeInputTokens:l},reason:t,strategy:u,removed:0,kept:this.messages.length,...s?{failure:s}:"manual"===t?{recoveryNotice:"当前内容未产生可用的压缩,已保留原上下文。"}:{}}),!1);if(this.isTurnAborted(s))return i&&s&&this.emitCancellation(e,s),d();if(!c)return d();try{const p=[...this.messages],h=this.compactionCheckpoint,m=be(this.capabilityManifest,ge.transcriptRead),g=void 0===h?void 0:3===h.version?h.taskSummary:ke(h,this.sessionManagerInstanceId,m),v=await X({messages:p,strategy:u,keepRecentTurns:c.keepRecentTurns,keepRecentTokens:c.keepRecentTokens,model:this.model,...void 0===g?{}:{previousSummary:g},...void 0===n?{}:{targetTokens:n},...void 0===this.contextWindow?{}:{contextWindow:this.contextWindow},...void 0===c.timeoutMs?{}:{timeoutMs:c.timeoutMs},...void 0===c.maxOutputTokens?{}:{maxOutputTokens:c.maxOutputTokens},...void 0===this.structuredOutputReasoning?{}:{structuredOutputReasoning:this.structuredOutputReasoning},...void 0===this.structuredOutputProviderOptions?{}:{structuredOutputProviderOptions:this.structuredOutputProviderOptions},...void 0===s?{}:{abortSignal:s.abortController.signal}});if(this.isTurnAborted(s))return i&&s&&this.emitCancellation(e,s),d();if(0===v.removed)return d();const f=v.summary??("truncate"===u?g??"Earlier messages were archived. Consult the original transcript for historical details.":void 0);if(void 0===f||0===f.trim().length)return d();if(Ee(v.messages).status===Me.repaired)return d();const b=this.currentCheckpointReminder(m),y=(e,t)=>void 0===r?this.requestBudgets.projectedMessageTokens(o({history:e,explicitSkill:{skillNames:[],userPrompt:"",modelUserContent:""},capabilityReminder:"",...void 0===t?{}:{checkpointReminder:t},system:this.systemPrompt,tools:this.modelTools(),project:e=>this.projectModelMessages(e)}).messages):this.requestBudgets.projectedMessageTokens(r(e,t)),T=y(p,b),C=new Error("compaction_candidate_did_not_shrink");let I=T;const k=e=>{const t=ke(e,this.sessionManagerInstanceId,m);if(I=y(v.messages,t),I>=T)throw C};let x;try{if(this.commitPersistedCompaction)x=this.commitPersistedCompaction({messages:v.messages,expectedActiveMessages:p,expectedLatestCheckpointId:h?.id,summary:f,validateCheckpoint:k});else{const e=this.listCompactionTranscriptEvidence(),t=this.listCompactionToolEvidence(),s=Se({summary:f,generation:(h?.generation??0)+1,...h?{previousCheckpointId:h.id}:{},transcript:{messages:{fromSequenceExclusive:-1,throughSequence:e.at(-1)?.sequence??h?.transcript.messages.throughSequence??-1},toolExecutions:{fromSequenceExclusive:-1,throughSequence:t.at(-1)?.sequence??h?.transcript.toolExecutions.throughSequence??-1},completeness:h?.transcript.completeness??"complete"},toolState:xe(e.map(e=>e.message),t)});k(s),this.onReplace?.(v.messages),x=s}}catch(e){if(e===C)return d();throw e}return this.messages.splice(0,this.messages.length,...v.messages),this.compactionCheckpoint=x,this.lastInputTokens=void 0,this.measuredProjectedTokens=void 0,e.push({type:"context-compacted",...void 0===l?{}:{beforeInputTokens:l},reason:t,strategy:u,removed:v.removed,kept:v.kept,checkpointId:x.id,checkpointGeneration:x.generation,checkpointSummaryStatus:"summarize"===u?"valid":"skipped"}),this.debug(e,"compaction","task summary committed",a,{removed:v.removed,kept:v.kept,beforeEstimatedTokens:T,afterEstimatedTokens:I}),!0}catch(e){throw d(this.isTurnAborted(s)?void 0:e instanceof Q?{reason:m.timeout,timeoutMs:e.timeoutMs}:{reason:m.error}),e}}async recoverFromContextError(e,t){if(!this.compaction?.enabled)return!1;try{return await this.runCompaction(e,"auto",t,!1,this.compactionTargetTokens())}catch(s){return this.isTurnAborted(t)||e.push({type:"error",stage:"plan",message:Je(s)}),!1}}isTurnAborted(e){return!0===e?.aborted||!0===e?.abortController.signal.aborted}execSessionIds(e){return[...e.execSessionIds].sort((e,t)=>e-t)}activeExecSessionIds(e){return this.execSessionIds(e).filter(e=>{const t=this.sessionManager?.get(e);return void 0!==t&&!E(t.state)})}interruptExecSessions(e){const t=this.execSessionIds(e);0!==t.length&&this.sessionManager?.interrupt(t).catch(e=>{process.stderr.write(`roll chat: 中断后台会话失败: ${Je(e)}\n`)})}abandonTurn(e){this.closed||this.activeTurn!==e||e.abortController.signal.aborted||(this.captureCancellationActivity(e),e.aborted=!0,e.cancellationReason??=O.runtime,this.gate.abortAll("本轮事件流已停止"),this.userInputInteractions.cancelAll("本轮事件流已停止"),this.interruptExecSessions(e),e.abortController.abort(P))}currentCancellationActivity(e){const t=this.activeExecSessionIds(e),s=[...e.pendingToolCalls.values()].filter(e=>this.toolCoordinator.hasExecutionStarted(e.executionOccurrence));return{execSessionIds:t,hadCompletedProgress:e.toolExecutions.length>0||e.completedStepResponses.size>0,hadInFlightWork:s.length>0||t.length>0,hadPotentialSideEffects:e.hadPotentialSideEffects||s.some(e=>e.potentialSideEffect)}}captureCancellationActivity(e){e.cancellationActivity??=this.currentCancellationActivity(e)}cancellationActivity(e){return e.cancellationActivity??this.currentCancellationActivity(e)}cancellationDisplayMessage(e){const t=e.cancellationReason??O.runtime,s=this.cancellationActivity(e);if(e.cancellationPersistenceAttempted&&!e.cancellationPersisted){const o=s.hadPotentialSideEffects?"部分操作可能已经执行,请先检查结果后再继续。":s.hadInFlightWork?"刚才的任务结果尚未确认,请先检查后再继续。":"请重新输入需要继续的内容。",i=e.userMessagePersisted?"本轮输入已保存,但进度或中断记录未能保存。":"刚才的对话和进度未能保存。";return t===O.timeout?`本轮等待时间过长,已自动停止。${i}${o}`:t===O.runtime?`本轮因运行异常而中断。${i}${o}`:`已停止本轮。${i}${o}`}const o=s.execSessionIds,i=be(this.capabilityManifest,ge.sessionList);switch(t){case O.user:return s.hadInFlightWork?s.hadPotentialSideEffects?"已停止本轮操作。正在进行的任务也已请求停止。之前的对话和已完成进度会保留;部分已经完成的操作不会自动撤销,请检查结果。":"已停止本轮操作。正在进行的任务也已请求停止。之前的对话和已完成进度会保留。":s.hadCompletedProgress?s.hadPotentialSideEffects?"已停止本轮回复。之前的对话和已完成进度会保留;部分已经完成的操作不会自动撤销,请检查结果。":"已停止本轮回复。之前的对话和已完成进度会保留,你可以继续输入。":"已停止本轮回复。之前的对话会保留,你可以继续输入。";case O.timeout:return 0===o.length?"本轮等待时间过长,已自动停止。之前的对话和已完成进度会保留,你可以继续输入或重试。":ye(this.capabilityManifest.lifecycle.hostMode)?"本轮等待时间过长,已自动停止。正在进行的任务会随本次命令结束而停止,之后无法继续查看;请先确认实际结果,再决定是否重试。":i?`本轮等待时间过长,但任务仍在运行(任务 #${o.join(", #")})。你可以在下一条消息中继续查看进度;确认结果前请勿重复执行。`:"本轮等待时间过长。任务可能仍在运行,但 Roll 暂时无法继续查看进度;请先确认实际结果,再决定是否重试。";case O.runtime:return s.hadInFlightWork?"本轮因运行异常而中断。正在进行的任务已请求停止,最终结果尚未确认;请检查结果后再继续。":s.hadPotentialSideEffects?"本轮因运行异常而中断。之前的对话和已完成进度会保留;部分已经完成的操作不会自动撤销,请检查结果后再继续。":"本轮因运行异常而中断。之前的对话会保留,你可以重试。"}}cancellationContextMessage(e){const t=e.cancellationReason??O.runtime,s=this.cancellationActivity(e).execSessionIds,o=s.length>0?`本轮后台任务编号: ${s.join(", ")}。`:"",i=be(this.capabilityManifest,ge.sessionList),n=Be;switch(t){case O.user:return`用户主动停止了本轮。${o}这些任务已收到停止请求;已完成的步骤和工具记录仍然有效,不要自动重复 outcome=success 的操作。${n}`;case O.timeout:{const e=void 0!==this.turnTimeoutMs?`(${String(this.turnTimeoutMs)}ms)`:"";return 0===s.length?`本轮因超时${e}停止。已完成的步骤和工具记录仍然有效。${n}`:ye(this.capabilityManifest.lifecycle.hostMode)?`本轮因超时${e}停止。${o}当前 one-shot 进程结束时会清理这些任务,后续 CLI 进程无法恢复。${n}`:i?`本轮因超时${e}停止,但后台任务仍在当前进程运行。${o}若且仅若最新用户明确要求继续或核对上一任务,可用 ${i} 找回并查看。${n}`:`本轮因超时${e}停止,但后台任务可能仍在运行。${o}当前没有可用的任务列表工具,不能安全恢复查看。${n}`}case O.runtime:return`本轮因运行异常中断。${o}已完成的步骤和工具记录仍然有效。${n}`}}emitCancellation(e,t){if(t.cancellationEventEmitted)return;t.cancellationReason??=O.runtime,t.cancellationEventEmitted=!0;const s=this.cancellationActivity(t).execSessionIds;e.push({type:"turn-cancelled",reason:t.cancellationReason,message:this.cancellationDisplayMessage(t),...s.length>0?{execSessionIds:s}:{}})}persistCancelledRecoveryTurn(e,t,s,o){const i=this.messages.length;t.userMessagePersisted||this.messages.push(s),this.persistCancelledTurn(e,t,i,o,Fe.ledgerOnly)}persistCancelledTurn(e,t,s,o,i=Fe.keepRaw){if(!this.persistPendingToolCancellationsOrReport(e,t,"取消工具账本持久化失败"))return this.messages.splice(s),t.cancellationPersistenceAttempted=!0,void this.emitCancellation(e,t);if(this.closed)return this.messages.splice(s),t.cancellationPersistenceAttempted=!0,void this.emitCancellation(e,t);if(!t.cancellationPersistenceAttempted){t.cancellationPersistenceAttempted=!0,this.messages.splice(s);const n=i===Fe.keepRaw,r=n?Ee(ct(Ke(t))).messages:[],a=n?Ge(t):Ve(t);t.cancellationPersisted=!0;const l=this.cancellationRecordMessages(t,a);t.cancellationPersisted=this.appendInterruptedTurnMessages(e,t,o,{rollbackTo:s,messages:[...r,...l],debugLabel:"persisting cancelled turn",failureLabel:"取消状态持久化失败"})}this.emitCancellation(e,t)}cancellationRecordMessages(e,t){return[de({context:this.cancellationContextMessage(e),completedMessages:t,toolExecutions:e.toolExecutions}),j(this.cancellationDisplayMessage(e),e.cancellationReason??O.runtime)]}persistPendingToolCancellationsOrReport(e,t,s){this.captureCancellationActivity(t);try{return this.persistPendingToolCancellations(e,t),!0}catch(t){return e.push({type:"error",stage:"execute",message:`${s}: ${Je(t)}`}),!1}}persistRecoveryCancellations(e,t){const s=[];for(const o of t.pendingToolCalls.values()){const i=D({kind:W.cancelled,reason:O.runtime,executionState:L.notExecuted},"模型连接中断,本工具调用确定未执行;重新生成的调用仍需正常校验与审批。"),n=G({toolCallId:o.toolCallId,agentName:o.agentName,toolName:o.toolName,input:o.input,result:i});this.persistToolExecution(n,t),e.push({type:"tool-result",toolCallId:o.toolCallId,agentName:o.agentName,toolName:o.toolName,executionId:n.id,outcome:i.outcome,display:i.display,output:i.display,isError:!0});const r=`${o.agentName}__${o.toolName}`;s.push({role:"assistant",content:[{type:"tool-call",toolCallId:o.toolCallId,toolName:r,input:o.input}]},{role:"tool",content:[{type:"tool-result",toolCallId:o.toolCallId,toolName:r,output:i.model}]}),t.pendingToolCalls.delete(o.toolCallId)}s.length>0&&(this.persistMessages(s,"raw_transcript"),this.messages.push(...s))}persistPendingToolCancellations(e,t){const s=t.cancellationReason??O.runtime;for(const o of t.pendingToolCalls.values()){const i=this.toolCoordinator.hasExecutionStarted(o.executionOccurrence)?L.outcomeUnknown:L.notExecuted,n=i===L.notExecuted?`工具调用在开始执行前因本轮 ${s} 中断而取消;确定未执行`:`工具调用已开始,因本轮 ${s} 中断而取消;最终结果尚未确认`,r=D({kind:W.cancelled,reason:s,executionState:i},n,{raw:{cancellationReason:s,executionState:i,abortReason:Je(t.abortController.signal.reason)}}),a=G({toolCallId:o.toolCallId,agentName:o.agentName,toolName:o.toolName,input:o.input,result:r});this.persistToolExecution(a,t),e.push({type:"tool-result",toolCallId:o.toolCallId,agentName:o.agentName,toolName:o.toolName,executionId:a.id,outcome:r.outcome,display:r.display,output:r.display,isError:!0}),t.pendingToolCalls.delete(o.toolCallId)}}cancel(){const e=this.activeTurn;return!!e&&(this.captureCancellationActivity(e),e.aborted=!0,e.cancellationReason=O.user,this.gate.abortAll("用户取消本轮"),this.userInputInteractions.cancelAll("用户取消本轮"),this.interruptExecSessions(e),e.abortController.abort(N),!0)}close(){if(void 0!==this.closePromise)return this.closePromise;this.closed=!0;const e=this.activeTurn;return e&&(this.captureCancellationActivity(e),e.aborted=!0,e.cancellationReason??=O.runtime,this.gate.abortAll(),this.userInputInteractions.cancelAll("Runtime 正在关闭"),e.abortController.abort(P)),this.closePromise=(async()=>{const e=(this.sessionManager?.close()??Promise.resolve([])).then(e=>{for(const t of e)void 0!==t.cleanupError&&process.stderr.write(`roll chat: 后台会话 ${String(t.sessionId)} 清理失败: ${t.cleanupError}\n`)},e=>{process.stderr.write(`roll chat: 会话 ${this.id} 后台清理失败: ${Je(e)}\n`)});await s(e,Le)||process.stderr.write(`roll chat: 会话 ${this.id} 在 ${String(Le)}ms 内未完成全部关闭步骤\n`);try{this.onClose?.()}catch(e){process.stderr.write(`roll chat: 会话 ${this.id} 关闭回调失败: ${Je(e)}\n`)}})(),this.closePromise}abort(){this.close().catch(e=>{process.stderr.write(`roll chat: 会话 ${this.id} 关闭失败: ${Je(e)}\n`)})}debug(e,t,s,o,i){this.debugEvents&&e.push({type:"debug",stage:t,message:s,...void 0!==o?{elapsedMs:Date.now()-o}:{},...void 0!==i?{data:i}:{}})}scheduleDebug(e,t,s,o,i){if(this.debugEvents)return setTimeout(()=>{this.debug(e,t,s,o,i)},5e3)}clearDebugTimer(e){void 0!==e&&clearTimeout(e)}}
1
+ import{describeAppOutput as e}from"@roll-agent/protocol";import{randomUUID as t}from"node:crypto";import{waitForPromiseSettlement as s}from"../bounded-wait.js";import{buildSessionModelRequest as o}from"./model-request.js";import{ModelRecoveryBudget as i}from"./model-recovery.js";import{ContextMaintenanceRequired as n,RequestBudgetTracker as r}from"./request-budget.js";import{buildUserMessageContent as a,normalizeSessionSendInput as l}from"./session-attachments.js";import{stepCountIs as c,streamText as u,wrapLanguageModel as d,InvalidToolInputError as p,NoOutputGeneratedError as h}from"ai";import{InvalidResponseDataError as m,JSONParseError as g,TypeValidationError as v}from"@ai-sdk/provider";import{COMPACTION_FAILURE_REASONS as f}from"../types/events.js";import{buildAgentToolset as b}from"../tool-bridge/build-tools.js";import{buildAgentInstallToolset as y}from"../tool-bridge/agent-install-tool.js";import{buildSkillToolset as T,skillInputErrorResult as C}from"../tool-bridge/skill-tool.js";import{buildScheduleToolset as I}from"../tool-bridge/schedule-tool.js";import{createInvalidScheduleRetryGuard as k}from"../tool-bridge/invalid-schedule-retry.js";import{buildFileToolset as x}from"../tool-bridge/file-tools/index.js";import{buildBashToolset as S}from"../tool-bridge/bash-tool.js";import{EXEC_COMMAND_NAME as w,EXEC_LIST_NAME as M,EXEC_POLL_NAME as E,buildSessionExecToolset as R}from"../tool-bridge/session-exec-tool.js";import{SessionManager as P}from"../bash/session/session-manager.js";import{isTerminalSessionState as O}from"../bash/session/types.js";import{withCleanEnv as A}from"../bash/clean-env.js";import{RUNTIME_CANCELLATION_ABORT_REASON as N,SESSION_CANCELLATION_REASONS as j,TURN_TIMEOUT_ABORT_REASON as q,USER_CANCELLATION_ABORT_REASON as $,createTurnCancellationMessage as L,isTurnTimeoutAbortReason as W}from"../types/cancellation.js";import{ToolRegistry as D}from"../tool-bridge/naming.js";import{TOOL_CANCELLATION_EXECUTION_STATES as F,TOOL_OUTCOME_KINDS as B,createToolResult as _,failedToolResult as U,isNormalizedToolResult as z,normalizeToolResult as H,readDisplayOutput as V,readToolOutcome as G}from"../tool-bridge/normalize-result.js";import{friendlyInvalidToolInputMessage as J}from"../tool-bridge/bounded-param.js";import{createToolExecutionRecord as K,toRedactedToolExecutionRecordSummary as Y}from"../tool-bridge/tool-execution-record.js";import{ToolExecutionCoordinator as Q}from"../tool-bridge/tool-execution-coordinator.js";import{ApprovalGate as X}from"../approval/approval-gate.js";import{SessionApprovalMemory as Z}from"../approval/approval-memory.js";import{CompactionTimeoutError as ee,compactMessages as te,estimateMessagesTokens as se,estimateTextTokens as oe,isCompactionSummaryAcknowledgement as ie,readCompactionSummaryPayload as ne}from"./compactor.js";import{AsyncEventQueue as re}from"./event-queue.js";import{ToolInputActivityTracker as ae}from"./tool-input-activity.js";import{projectTurnInputSkillCheckpoint as le,turnInputSkillCheckpointSchema as ce}from"../store/turn-input.js";import{attachExplicitSkillCheckpoint as ue,prepareExplicitSkillContext as de,readExplicitSkillCheckpoint as pe,stripExplicitSkillCheckpoints as he}from"./explicit-skill-context.js";import{createCancelledTurnRecoveryMessage as me,createToolLedgerGapRecoveryMessage as ge,stripCancelledTurnRecoveryMessages as ve}from"./cancelled-turn-recovery.js";import{CAPABILITY_HOST_MODES as fe,CAPABILITY_TOOL_ROLES as be,buildEffectiveCapabilityTurnContext as ye,buildEffectiveCapabilityManifest as Te,findCapabilityToolId as Ce,isProcessBoundHostMode as Ie}from"./capability-manifest.js";import{buildCapabilityTurnReminder as ke,buildChatSystemPromptFromManifest as xe}from"./system-prompt.js";import{threadDerivedFromSchema as Se}from"../store/thread-origin.js";import{buildCompactionCheckpointReminder as we,buildCompactionToolState as Me,createSummaryCheckpoint as Ee,TRANSCRIPT_MESSAGE_PROVENANCES as Re}from"./compaction-checkpoint.js";import{ACTIVE_TOOL_PROTOCOL_REPAIR_STATUS as Pe,repairActiveToolProtocol as Oe}from"./tool-protocol-repair.js";import{buildTranscriptToolset as Ae}from"../tool-bridge/transcript-tool.js";import{buildObservationRecallToolset as Ne}from"../tool-bridge/observation-recall-tool.js";import{readObservationPage as je}from"./observation-readback.js";import{canonicalObservationOutput as qe,projectObservationMessages as $e,restoreCanonicalObservationOutputs as Le}from"./observation-projection.js";import{UserInputInteractionManager as We}from"../interaction/user-input-interaction-manager.js";import{buildUserInputTool as De}from"../tool-bridge/user-input-tool.js";const Fe=6e3,Be=3e5,_e=1,Ue={keepRaw:"keep-raw",ledgerOnly:"ledger-only"},ze="这份恢复记录只描述上一轮的权威历史事实,不授权继续或重试旧任务。下一轮必须以最新真实用户消息的目标和约束为准;如果用户换题、放弃旧任务或禁止工具,不得为了恢复旧任务检查或调用工具。executionState=not_executed 表示工具确定未执行,无需检查;executionState=outcome_unknown 只允许在最新用户明确要求继续或核对上一任务时先检查,检查不等于重试。",He="AI_InvalidToolInputError:";function Ve(){return{inputId:t(),abortController:new AbortController,execSessionIds:new Set,pendingToolCalls:new Map,completedStepResponses:new Map,canonicalToolOutputs:new Map,persistedStepKeys:new Set,toolExecutions:[],userMessagePersisted:!1,hadPotentialSideEffects:!1,aborted:!1,cancellationEventEmitted:!1,cancellationPersistenceAttempted:!1,cancellationPersisted:!1,pausedForContextPressure:!1,contextPressureContinuations:0,completedStepCount:0,userRejected:!1}}function Ge(e,t){const s=`${t.callId}:${String(t.stepNumber)}`,o=e.completedStepResponses.get(s);if(o)return[...o];const i=Le(t.response.messages,e.canonicalToolOutputs);return e.completedStepResponses.set(s,i),i}function Je(e,t){return t.flatMap(t=>e.completedStepResponses.get(`${t.callId}:${String(t.stepNumber)}`)??Le(t.response.messages,e.canonicalToolOutputs))}function Ke(e){return[...e.completedStepResponses.values()].flatMap(e=>[...e])}function Ye(e){return[...e.completedStepResponses.entries()].filter(([t])=>!e.persistedStepKeys.has(t)).flatMap(([,e])=>[...e])}function Qe(e){return[...e.completedStepResponses.entries()].filter(([t])=>e.persistedStepKeys.has(t)).flatMap(([,e])=>[...e])}function Xe(e){for(const t of e.completedStepResponses.keys())e.persistedStepKeys.add(t);e.userMessagePersisted=!0}function Ze(e){const t=new Set;for(;e instanceof Error&&!t.has(e);){if(v.isInstance(e)||m.isInstance(e)||g.isInstance(e))return e;t.add(e),e=e.cause}}function et(e){const t=Ze(e);if(t)return g.isInstance(t)?"模型调用返回了无效的 JSON。":"模型调用的数据未通过格式校验。"}function tt(e){if(e instanceof Error){const t=Ze(e);return t===e?"数据格式无效。":t?.message?e.message.replaceAll(t.message,"数据格式无效。"):e.message}if("object"==typeof e&&null!==e){if("message"in e&&"string"==typeof e.message&&e.message.length>0)return e.message;const t=st(e);if(void 0!==t&&"{}"!==t)return t}return String(e)}function st(e){try{return JSON.stringify(e)??void 0}catch{return}}function ot(e){return"user"===e.role&&"string"==typeof e.content&&void 0!==ne(e.content)||"assistant"===e.role&&ie(e.content)}function it(e,t){return t.aborted?Promise.reject(t.reason):new Promise((s,o)=>{let i=!1;const n=e=>{i||(i=!0,t.removeEventListener("abort",r),e())},r=()=>n(()=>o(t.reason));t.addEventListener("abort",r,{once:!0}),Promise.resolve(e).then(e=>n(()=>s(e)),e=>n(()=>o(e)))})}function nt(e){return tt(V(e))}function rt(e){return p.isInstance(e)||"string"==typeof e&&e.startsWith(He)?B.invalidInput:B.toolFailed}function at(){return({steps:e})=>e.at(-1)?.toolResults.some(e=>G(e.output).kind===B.userRejected)??!1}function lt(e){return/context[_ -]?length|context window|maximum context|token limit|too many tokens|prompt is too long|input is too long/i.test(et(e)??tt(e))}function ct(e){const t=e.inputTokenDetails?.cacheReadTokens,s=e.inputTokenDetails?.cacheWriteTokens,o=e.outputTokenDetails?.reasoningTokens;return{...void 0!==e.inputTokens?{inputTokens:e.inputTokens}:{},...void 0!==e.outputTokens?{outputTokens:e.outputTokens}:{},...void 0!==e.totalTokens?{totalTokens:e.totalTokens}:{},...void 0!==t?{cachedInputTokens:t}:{},...void 0!==s?{cacheWriteTokens:s}:{},...void 0!==o?{reasoningTokens:o}:{}}}function ut(e,t){return void 0===e&&void 0===t?void 0:(e??0)+(t??0)}function dt(e,t){const s=ut(e.cachedInputTokens,t.cachedInputTokens),o=ut(e.cacheWriteTokens,t.cacheWriteTokens),i=ut(e.reasoningTokens,t.reasoningTokens);return{inputTokens:(e.inputTokens??0)+(t.inputTokens??0),outputTokens:(e.outputTokens??0)+(t.outputTokens??0),totalTokens:(e.totalTokens??0)+(t.totalTokens??0),...void 0!==s?{cachedInputTokens:s}:{},...void 0!==o?{cacheWriteTokens:o}:{},...void 0!==i?{reasoningTokens:i}:{}}}function pt(e,t){const s=e.trim(),o=t.trim();return s.length>0&&o.length>0&&o.startsWith(s)}function ht(e,t){return void 0!==e?e:W(t)?j.timeout:j.runtime}function mt(e){return e.flatMap(e=>{if("assistant"!==e.role||!Array.isArray(e.content))return[e];const t=e.content.filter(e=>"reasoning"!==e.type);return 0===t.length?[]:t.length===e.content.length?[e]:[{...e,content:t}]})}function gt(e,t,s){for(const o of Object.keys(t))e[o]=s}function vt(e,t,s){const o={[w]:be.sessionCommand,[E]:be.sessionPoll,[M]:be.sessionList};for(const i of Object.keys(t)){const t=s.resolve(i),n=t?o[t.toolName]:void 0;n&&(e[i]=n)}}export class AgentSession{id;model;resolveReasoningPresentation;modelRecovery;maxSteps;messages;onPersist;onReplace;onToolExecution;listPersistedToolExecutions;getPersistedToolExecution;recoverPersistedToolExecutionContext;listPersistedTranscriptMessages;commitPersistedCompaction;inMemoryToolExecutions=[];uncoveredToolExecutions=new Map;inMemoryTranscript=[];contextWindow;compaction;turnTimeoutMs;onClose;onBeforeTurn;providerOptions;structuredOutputProviderOptions;structuredOutputReasoning;onProviderOptionsChange;debugEvents;policy;systemPrompt;explicitSystemPrompt;derivedFrom;lastExtraPrompt;workspaceInstructions;appliedWorkspaceInstructions;capabilityContext;resolveDynamicCapabilityContext;capabilityManifest;lastCapabilityTurnContext;toolRoles;skillSummaries;skillLibrary;skillExecutionLibrary;skillToolId;refreshSkillLibrary;toolSourceAgentNames;toolSchemaPolicy;onToolExcluded;agentToolSchemaIssues=new Map;excludedToolIds=new Set;gate=new X;userInputInteractions=new We;onAcceptInput;onRecordInputSkillCheckpoint;getInputSkillCheckpoint;inputSkillCheckpoints=new Map;toolCoordinator=new Q;tools;registry;observationRecallToolId;observationRetentionByToolId=new Map;observationResultIds=new Map;ambiguousObservationCallIds=new Set;userInputToolId;userInputTool;userInputAvailable=!1;sessionManager;sessionManagerInstanceId=t();compactionCheckpoint;emit;activeTurn;closePromise;closed=!1;sessionUsage={inputTokens:0,outputTokens:0,totalTokens:0};lastInputTokens;measuredProjectedTokens;promptOverhead;requestBudgets=new r;contextWindowSource;constructor(e){this.id=e.id,this.model=e.model,this.resolveReasoningPresentation=e.resolveReasoningPresentation,this.modelRecovery=e.modelRecovery,this.contextWindowSource=e.contextWindowSource,this.maxSteps=e.maxSteps;const t=e.initialMessages?mt(e.initialMessages):[];this.messages=[...Oe(t).messages],this.onPersist=e.onPersist,this.onAcceptInput=e.onAcceptInput,this.onRecordInputSkillCheckpoint=e.onRecordInputSkillCheckpoint,this.getInputSkillCheckpoint=e.getInputSkillCheckpoint,this.onReplace=e.onReplace,this.onToolExecution=e.onToolExecution,this.listPersistedToolExecutions=e.listToolExecutions,this.getPersistedToolExecution=e.getToolExecution,this.recoverPersistedToolExecutionContext=e.recoverUncoveredToolExecutions,this.listPersistedTranscriptMessages=e.listTranscriptMessages,this.commitPersistedCompaction=e.commitCompaction,this.compactionCheckpoint=e.initialCheckpoint;let s=(e.initialCheckpoint?.transcript.messages.throughSequence??-1)+1;for(const e of this.messages)ot(e)||(this.inMemoryTranscript.push({sequence:s,provenance:Re[0],createdAt:new Date(0).toISOString(),message:e}),s+=1);this.contextWindow=e.contextWindow,this.compaction=e.compaction,this.turnTimeoutMs=e.turnTimeoutMs,this.onClose=e.onClose,this.onBeforeTurn=e.onBeforeTurn,this.providerOptions=e.providerOptions,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.onProviderOptionsChange=e.onProviderOptionsChange,this.debugEvents=e.debugEvents??!1,this.policy=e.policy,this.explicitSystemPrompt=e.systemPrompt,this.derivedFrom=void 0===e.derivedFrom?void 0:Se.parse(e.derivedFrom),this.workspaceInstructions=e.workspaceInstructions,this.resolveDynamicCapabilityContext=e.resolveDynamicCapabilityContext,this.skillLibrary=e.skillLibrary,this.skillExecutionLibrary=e.skillLibrary,this.refreshSkillLibrary=e.refreshSkillLibrary,this.skillSummaries=e.skillLibrary?.list()??[],this.toolSourceAgentNames=new Set(e.sources.map(e=>e.agentName)),this.toolSchemaPolicy=e.toolSchemaPolicy,this.onToolExcluded=e.onToolExcluded;const o=new D,i={},n=De({sessionId:this.id,isAvailable:()=>this.userInputAvailable,request:(e,t)=>this.requestUserInput(e,t)},o,this.toolCoordinator);this.userInputToolId=n.id,this.userInputTool=n.tools,gt(i,n.tools,be.userInput);const r=e.readCheckpointTranscript?Ae(e.readCheckpointTranscript,o,this.toolCoordinator,`thread:${this.id}:transcript`):{};gt(i,r,be.transcriptRead);const a=e.skillLibrary?this.buildSkillTools(o):{};gt(i,a,be.skill);const l=new Z,c=e.fileTools?x(e.fileTools,o,{...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator,approvalMemory:l}):void 0;c&&(gt(i,c.readTools,be.fileRead),gt(i,c.editTools,be.fileEdit),gt(i,c.verifyTools,be.fileVerify));const u={...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),emitEvent:e=>this.emit?.(e),coordinator:this.toolCoordinator},d=e.bashClassifier?{classifier:e.bashClassifier}:{},p=e.bash?S(e.bash,o,u,d):{};gt(i,p,be.shell),e.bashSession&&(this.sessionManager=new P({maxSessions:e.bashSession.maxSessions,profile:e.bashSession.profile,env:A(e.bashSession.env??process.env),bufferCapacity:e.bashSession.bufferCapacity,...e.bashSession.onCommandSpawn?{onSpawn:e.bashSession.onCommandSpawn}:{}}));const h=e.bashSession&&this.sessionManager?R({workdir:e.bashSession.workdir,defaultYieldMs:e.bashSession.defaultYieldMs,maxOutputTokens:e.bashSession.maxOutputTokens,...e.bashSession.env?{env:e.bashSession.env}:{}},this.sessionManager,o,u,{...d,onSessionTouched:e=>this.activeTurn?.execSessionIds.add(e)}):{};vt(i,h,o);const m=e.agentInstall,g=m?y({catalog:m.catalog,install:async(e,t)=>{const s=await m.install(e,t);return s.outcome.ok&&s.refresh?(this.applyAgentRefresh(s.refresh),{...s.outcome,refreshApplied:!0}):s.outcome}},o,{...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator}):{};gt(i,g,be.agentInstall);const v=e.schedules?I(e.schedules,o,{...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator}):{createTools:{},extendTools:{},listTools:{}};gt(i,v.createTools,be.scheduleCreate),gt(i,v.extendTools,be.scheduleExtend),gt(i,v.listTools,be.scheduleList);const f=b(e.sources,{...e.policy?{policy:e.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator},o);gt(i,f.tools,be.agent);const T=f.observationRetentionByToolId.size>0?Ne(e=>this.readObservation(e),o,this.toolCoordinator,`thread:${this.id}:observation`):{};this.observationRecallToolId=Object.keys(T)[0],gt(i,T,be.observationRead),this.tools={...r,...T,...a,...c?{...c.readTools,...c.editTools,...c.verifyTools}:{},...p,...h,...g,...v.createTools,...v.extendTools,...v.listTools,...f.tools},this.registry=f.registry;for(const[e,t]of f.observationRetentionByToolId)this.observationRetentionByToolId.set(e,t);this.toolRoles=i,this.recordToolSchemaIssues(f.schemaIssuesByToolId),this.applyToolSchemaPolicy(),this.capabilityContext=e.capabilityContext??{profile:e.bash?.profile.toolName??"no-shell",cwd:e.bash?.workdir??process.cwd(),platform:process.platform,...e.bash?{shellHints:e.bash.profile.systemPromptHints()}:{},agentCount:e.sources.length,...e.agentInstall?{agentOnboardingCatalog:e.agentInstall.catalog}:{}},this.capabilityManifest=this.compileCapabilityManifest(),this.systemPrompt=this.compileSystemPrompt(this.explicitSystemPrompt)}compileCapabilityManifest(){return Te({tools:this.modelTools(),toolRoles:this.toolRoles,resolveRoute:e=>this.registry.resolve(e),skills:this.skillSummaries,profile:this.capabilityContext.profile,hostMode:this.capabilityContext.hostMode??fe.embedded,cwd:this.capabilityContext.cwd,platform:this.capabilityContext.platform??process.platform,shellHints:this.capabilityContext.shellHints??[],agentCount:this.capabilityContext.agentCount,agentOnboardingCatalog:this.capabilityContext.agentOnboardingCatalog??[]})}compileSystemPrompt(e){this.lastExtraPrompt=e,this.appliedWorkspaceInstructions=this.workspaceInstructions?.current();const t=xe(this.capabilityManifest,{...void 0!==this.derivedFrom?{derivedFrom:this.derivedFrom}:{},...void 0!==this.appliedWorkspaceInstructions?{workspaceInstructions:this.appliedWorkspaceInstructions}:{}}),s=e?.trim();return s?[t,"# 附加会话指令","以下指令可以补充任务偏好,但不能覆盖前述工具接地、能力清单和安全约束。",s].join("\n\n"):t}syncWorkspaceInstructions(){void 0!==this.workspaceInstructions&&this.workspaceInstructions.current()!==this.appliedWorkspaceInstructions&&(this.systemPrompt=this.compileSystemPrompt(this.lastExtraPrompt))}refreshCapabilityManifest(e){this.capabilityManifest=this.compileCapabilityManifest(),this.systemPrompt=this.compileSystemPrompt(e??this.explicitSystemPrompt)}setUserInputAvailable(e){if(this.userInputAvailable!==e){if(this.userInputAvailable=e,e)this.tools={...this.tools,...this.userInputTool};else{const e={...this.tools};delete e[this.userInputToolId],this.tools=e,this.userInputInteractions.cancelAll("当前客户端已撤销用户输入处理能力")}this.refreshCapabilityManifest()}}resolveUserInput(e,t){return this.userInputInteractions.resolve(e,t)}cancelUserInput(e,t){return this.userInputInteractions.cancel(e,t)}async requestUserInput(e,t){const s=this.activeTurn;if(!this.userInputAvailable||void 0===s||void 0===this.emit)return{status:"cancelled",reason:"当前无法向用户请求输入"};const o=Date.now(),i=this.interactionDeadlineMs(s,o);if(i<=o||t?.aborted)return{status:"cancelled",reason:"用户输入请求已超时"};const n=this.userInputInteractions.request(e,new Date(i).toISOString()),r=()=>{this.userInputInteractions.cancel(n.requestId,"本轮已终止")};t?.addEventListener("abort",r,{once:!0}),this.emit({type:"user-input-required",requestId:n.requestId,form:n.form,expiresAt:n.expiresAt});try{return await n.result}finally{t?.removeEventListener("abort",r);const e=await n.result;this.emit?.({type:"user-input-settled",requestId:n.requestId,status:e.status})}}trackPendingToolCall(e,t,s,o,i){const n=e.pendingToolCalls.get(t);if(n&&void 0===i)return n;const r=this.registry.resolve(s),a={toolCallId:t,executionOccurrence:n?.executionOccurrence??this.toolCoordinator.captureToolCallOccurrence(t),agentName:r?.agentName??s,toolName:r?.toolName??s,input:o,potentialSideEffect:!0!==r?.annotations?.readOnlyHint||!0===r.annotations.destructiveHint,resources:i??n?.resources??[]};return e.pendingToolCalls.set(t,a),a}buildSkillTools(e){const t=T(()=>{if(!this.skillExecutionLibrary)throw new Error("skill library 不可用");return this.skillExecutionLibrary},e,this.toolCoordinator,{...void 0===this.skillToolId?{}:{toolId:this.skillToolId},names:this.skillSummaries.map(e=>e.name)});return this.skillToolId??=Object.keys(t)[0],t}applySkillLibrary(e){const t=e?.list()??[],s=t.length!==this.skillSummaries.length||t.some((e,t)=>e.name!==this.skillSummaries[t]?.name),o=JSON.stringify(t)!==JSON.stringify(this.skillSummaries);if(this.skillLibrary=e,this.skillSummaries=t,s){if(void 0!==this.skillToolId){const e={...this.tools};delete e[this.skillToolId],delete this.toolRoles[this.skillToolId],this.tools=e}const e=this.buildSkillTools(this.registry);gt(this.toolRoles,e,be.skill),this.tools={...this.tools,...e}}o&&this.refreshCapabilityManifest()}async refreshSkills(e){if(void 0!==this.refreshSkillLibrary){const t=await it(this.refreshSkillLibrary(e),e);e.throwIfAborted(),this.applySkillLibrary(t)}this.skillExecutionLibrary=this.skillLibrary}skillToolInputError(e,t){return e===this.skillToolId&&void 0!==this.skillExecutionLibrary?C(this.skillExecutionLibrary,t):void 0}applyAgentRefresh(e){if(!this.toolSourceAgentNames.has(e.source.agentName)){const t=b([e.source],{...this.policy?{policy:this.policy}:{},requestApproval:e=>this.requestApproval(e),coordinator:this.toolCoordinator},this.registry);gt(this.toolRoles,t.tools,be.agent),this.tools={...this.tools,...t.tools};for(const[e,s]of t.observationRetentionByToolId)this.observationRetentionByToolId.set(e,s);if(void 0===this.observationRecallToolId&&this.observationRetentionByToolId.size>0){const e=Ne(e=>this.readObservation(e),this.registry,this.toolCoordinator,`thread:${this.id}:observation`);this.observationRecallToolId=Object.keys(e)[0],gt(this.toolRoles,e,be.observationRead),this.tools={...this.tools,...e}}this.recordToolSchemaIssues(t.schemaIssuesByToolId),this.applyToolSchemaPolicy(),this.toolSourceAgentNames.add(e.source.agentName)}e.skillLibrary&&this.applySkillLibrary(e.skillLibrary),e.capabilityContext&&(this.capabilityContext=e.capabilityContext),this.refreshCapabilityManifest(e.systemPrompt)}async*send(e){if(this.closed)throw new Error("session is closed");if(this.activeTurn)throw new Error("session already has an active turn");this.onBeforeTurn?.();const t=l(e),s=new re;this.emit=e=>s.push(e);const o=Ve();this.activeTurn=o,this.runTurn(s,o,t).catch(e=>{s.push({type:"error",stage:"execute",message:tt(e)}),s.close()});try{for await(const e of s)yield e}finally{this.activeTurn===o&&this.abandonTurn(o),void 0!==this.emit&&(this.emit=void 0)}}async*compact(e="manual"){if(this.closed)throw new Error("session is closed");if(this.activeTurn)throw new Error("session already has an active turn");this.onBeforeTurn?.();const t=new re;this.emit=e=>t.push(e);const s=Ve();this.activeTurn=s,this.runCompactionTurn(t,s,e).catch(e=>{t.push({type:"error",stage:"plan",message:tt(e)}),t.close()});try{for await(const e of t)yield e}finally{this.activeTurn===s&&this.abandonTurn(s),void 0!==this.emit&&(this.emit=void 0)}}async runTurn(s,r,l){const m=Date.now(),g=this.modelRecovery,v=void 0===g?void 0:new i(g);let f,b,y;const T=()=>{r.abortController.signal.aborted||(this.captureCancellationActivity(r),r.aborted=!0,r.cancellationReason=j.timeout,this.gate.abortAll("本轮运行超时"),this.userInputInteractions.cancelAll("本轮运行超时"),r.abortController.abort(q))},C=a(l.text,l.attachments);try{g?.onTurnStart?.();const i={role:"user",content:C};let a;try{void 0!==this.onAcceptInput?a=this.onAcceptInput(r.inputId,i).transcriptSequence:(a=(this.listCompactionTranscriptEvidence().at(-1)?.sequence??-1)+1,this.onPersist?.([i])),this.recordPersistedMessagesInMemory([i]),this.messages.push(i),r.userMessagePersisted=!0,b=this.messages.length}catch(e){return void s.push({type:"error",stage:"plan",message:`输入持久化失败,未开始模型请求: ${tt(e)}`})}if(void 0!==this.turnTimeoutMs){const e=Math.max(0,this.turnTimeoutMs-(Date.now()-m));r.expiresAt=new Date(m+this.turnTimeoutMs).toISOString(),y=setTimeout(T,e),0===e&&T()}this.debug(s,"turn","start",m,{messages:this.messages.length,tools:Object.keys(this.modelTools()).length,maxSteps:this.maxSteps,...l.attachments.length>0?{attachments:l.attachments.length}:{},...void 0!==this.contextWindow?{contextWindow:this.contextWindow}:{},...void 0!==this.lastInputTokens?{lastInputTokens:this.lastInputTokens}:{}});try{this.reconcileUncoveredToolExecutionContext()}catch(e){return void s.push({type:"error",stage:"plan",message:`工具执行恢复状态持久化失败: ${tt(e)}`})}if(b=this.messages.length,this.isTurnAborted(r))return void this.persistCancelledTurn(s,r,b,m);this.syncWorkspaceInstructions(),await this.refreshSkills(r.abortController.signal);let I,x=!0,S=0,w=!1;const M=()=>Math.max(1024,.05*(this.contextWindow??0)),E=e=>void 0===I||e>=I.calibratedInputEstimate+M(),R=new Set;let P;const O=k(),A=de({rawInput:l.text,skillSummaries:this.skillSummaries,skillLibrary:this.skillLibrary});void 0!==r.expiresAt&&Date.now()>=Date.parse(r.expiresAt)&&T();const N=i;if(A.skillNames.length>0&&!this.isTurnAborted(r)){const e=pe(ue(i,A));if(void 0===e)throw new Error("Explicit Skill checkpoint could not be created");this.onRecordInputSkillCheckpoint?.(r.inputId,e),this.inputSkillCheckpoints.set(a,ce.parse(e))}if(b=this.messages.length,this.isTurnAborted(r))return void this.persistCancelledTurn(s,r,b,m);s.push({type:"message-start",messageId:t()});let q={};try{q=await it(this.resolveDynamicCapabilityContext?.(r.abortController.signal)??{},r.abortController.signal)??{}}catch(e){if(this.isTurnAborted(r))return b=this.messages.length,r.cancellationReason=ht(r.cancellationReason,r.abortController.signal.reason??e),void this.persistCancelledTurn(s,r,b,m);this.debug(s,"turn","dynamic capability context unavailable",m,{message:tt(e)})}const $=ye(this.capabilityManifest,{explicitSkillNames:A.skillNames,...q.ruleIds?{ruleIds:q.ruleIds}:{},...q.vcs?{vcs:q.vcs}:{},...q.origin?{origin:q.origin}:{},sessions:(this.sessionManager?.list()??[]).map(e=>({sessionId:e.sessionId,state:e.state}))});this.lastCapabilityTurnContext=$;const L=ke($);let D;for(;;){b=this.messages.length,r.pausedForContextPressure=!1;const i=Ce(this.capabilityManifest,be.transcriptRead),a=this.currentCheckpointReminder(i),l=void 0===a?0:oe(a),y=this.modelTools(),T=(e=[])=>o({history:this.messages,completedMessages:e,explicitSkill:A,capabilityReminder:L,...void 0===a?{}:{checkpointReminder:a},system:this.systemPrompt,tools:y,...void 0===this.providerOptions?{}:{providerOptions:this.providerOptions},project:e=>this.projectModelMessages(e)}),C=T();let k=C.shapeContext;this.debug(s,"model","calling streamText",m,{messages:this.messages.length,tools:Object.keys(this.modelTools()).length,contextRecoveryAttempts:S,...void 0!==this.turnTimeoutMs?{timeoutMs:this.turnTimeoutMs}:{}});let q,$=0,F=0;const _=[];let V,G,Y,Q=!1;const X=d({model:this.model,middleware:{specificationVersion:"v4",wrapStream:async({params:e,doStream:t})=>{if(r.abortController.signal.aborted)throw r.abortController.signal.reason;const s=this.requestBudgets.prepare(e,{provider:this.model.provider,model:this.model.modelId,...void 0===this.contextWindow?{}:{window:this.contextWindow},...void 0===this.contextWindowSource?{}:{windowSource:this.contextWindowSource},threshold:this.compaction?.threshold??.75},k,r.inputId),o=s.maintenanceTarget,i=this.modelTools(),a=Object.keys(i).length!==Object.keys(y).length||Object.entries(y).some(([e,t])=>i[e]!==t),l=void 0!==s.availableInputCeiling&&s.calibratedInputEstimate>s.availableInputCeiling,c=!w&&!0===this.compaction?.enabled&&void 0!==o&&s.calibratedInputEstimate>=o&&(E(s.calibratedInputEstimate)||void 0!==I&&(s.shapeFingerprint!==I.shapeFingerprint||s.rawInputEstimate>=I.rawInputEstimate+M())),u=R.has(s.fingerprint)||void 0!==P&&s.rawInputEstimate>=P.rawInputEstimate;if(a||l||c||u)throw a&&(x=!0),V=new n(s,a?"shape_changed":u?"provider_rejected":l?"budget":"soft_target"),V;w=!1,G=s,this.requestBudgets.dispatchedRequest(),Q=!1;const d=await t();if(void 0===g)return d;const p=d.stream.getReader();let h=!1;return{...d,stream:new ReadableStream({async pull(e){let t;try{t=await p.read()}catch(t){return Q=!1,e.enqueue({type:"error",error:t}),e.close(),void p.releaseLock()}if(t.done)return e.close(),void p.releaseLock();const s=t.value;if("finish"!==s.type||!h){if("finish"===s.type&&"error"===s.finishReason.unified)return h=!0,Q=!1,void e.enqueue({type:"error",error:new Error("模型未成功完成本步骤,未执行待处理工具。")});"finish"===s.type&&(Q=!0),"error"===s.type&&(Q=!1,h=!0),e.enqueue(s)}},async cancel(e){try{await p.cancel(e)}finally{p.releaseLock()}}})}}}}),Z=this.providerOptions,ee=this.resolveReasoningPresentation?.(this.model,Z),te=()=>u({model:X,...ee?{include:{rawChunks:!0}}:{},...void 0===g?{}:{maxRetries:0},system:C.system,messages:C.messages,tools:y,prepareStep:async()=>{x||await this.refreshSkills(r.abortController.signal),x=!1,$=se(this.projectModelMessages([...this.messages,..._]));const e=T(_);return k=e.shapeContext,F=this.requestBudgets.projectedMessageTokens(e.messages),{messages:e.messages,system:e.system}},stopWhen:[()=>void 0!==g&&!Q,c(Math.max(1,this.maxSteps-r.completedStepCount)),at(),O.stop,this.stopOnContextPressure(r,()=>$,()=>this.requestBudgets.predict(T(_).messages,F),E)],toolApproval:async({toolCall:e})=>{this.trackPendingToolCall(r,e.toolCallId,e.toolName,e.input),await this.toolCoordinator.prepare(e.toolCallId,e.toolName,e.input)},onLanguageModelCallStart:({callId:e})=>this.toolCoordinator.startBatch(e),onLanguageModelCallEnd:({callId:e,content:t,usage:s,finishReason:o})=>{if(void 0===g||"error"!==o){for(const e of t){if("tool-call"!==e.type||!("invalid"in e)||!0!==e.invalid)continue;const t=this.skillToolInputError(e.toolName,e.input);void 0!==t&&r.canonicalToolOutputs.set(e.toolCallId,t.model)}Y=dt(Y??{},ct(s)),void 0!==G&&this.requestBudgets.measured(G,s.inputTokens),this.toolCoordinator.sealBatch(e,t.flatMap(e=>"tool-call"!==e.type||!0===e.providerExecuted||"invalid"in e&&!0===e.invalid?[]:[{toolCallId:e.toolCallId,toolId:e.toolName}]))}},abortSignal:r.abortController.signal,...Z?{providerOptions:Z}:{},onError:()=>{},onStepEnd:e=>{(void 0===g||Q)&&_.push(...Ge(r,e))},onAbort:({steps:e})=>{if(void 0===g)for(const t of e)Ge(r,t)}});let ie;try{ie=te()}catch(e){if(this.isTurnAborted(r)||W(e))return r.aborted=!0,r.cancellationReason=ht(r.cancellationReason,e),void this.persistCancelledTurn(s,r,b,m);if(!lt(e))throw e;this.messages.splice(b);const t=S<1,o=!!t&&await this.recoverFromContextError(s,r);if(this.isTurnAborted(r))return void this.persistCancelledRecoveryTurn(s,r,N,m);if(o&&t){S+=1;continue}return this.persistContextFailure(s,r,N,!1,m),void s.push({type:"error",stage:"execute",message:tt(e)})}this.debug(s,"model","streamText returned",m);let ne,re,le,ce,ue,de,pe,he="",me="",ge=!1,ve=0,fe=!1,ye=!1,Te=!1;const Ie=this.scheduleDebug(s,"model","waiting for first stream event",m,{messages:this.messages.length}),ke=new ae(e=>{const t=this.registry.resolve(e);return void 0===t?void 0:`${t.agentName}.${t.toolName}`},e=>s.push(e)),xe=()=>ke.clear();r.abortController.signal.addEventListener("abort",xe,{once:!0});try{let t,o=0;for await(const i of ie.fullStream){if(this.closed){r.aborted=!0,r.cancellationReason??=j.runtime;break}switch(Te||(Te=!0,this.clearDebugTimer(Ie),this.debug(s,"model","first stream event",m,{part:i.type})),i.type){case"start-step":t=void 0,void 0!==g&&s.push({type:"model-step-start"});break;case"tool-input-start":ke.start(i.id,i.toolName);break;case"tool-input-delta":ke.delta(i.id);break;case"tool-input-end":ke.end(i.id);break;case"raw":t=ee?.readDeltas(i.rawValue),o=0;break;case"reasoning-start":s.push({type:"reasoning-start",reasoningId:i.id});break;case"reasoning-delta":{const e=t?.[o]===i.text?ee?.kind:void 0;e?o++:t=void 0,s.push({type:"reasoning-delta",reasoningId:i.id,delta:i.text,...e?{presentation:e}:{}});break}case"reasoning-end":s.push({type:"reasoning-end",reasoningId:i.id});break;case"text-delta":if(!ge){const e=me+i.text;if(pt(e,A.userPrompt)){me=e;break}if(me.length>0){const e=me+i.text;me="",he+=e,s.push({type:"text-delta",delta:e});break}}he+=i.text,s.push({type:"text-delta",delta:i.text});break;case"tool-call":{ke.end(i.toolCallId),ge=!0,me="";const e=this.trackPendingToolCall(r,i.toolCallId,i.toolName,i.input,this.toolCoordinator.describeResources(i.toolName,i.input));s.push({type:"tool-call",toolCallId:i.toolCallId,agentName:e.agentName,toolName:e.toolName,input:i.input});break}case"tool-result":{const t=this.registry.resolve(i.toolName),o=r.pendingToolCalls.get(i.toolCallId),n=z(i.output)?i.output:H(i.output),a=n.outcome,l=n.display,c=K({toolCallId:i.toolCallId,agentName:t?.agentName??i.toolName,toolName:t?.toolName??i.toolName,input:o?.input,result:n});this.persistToolExecution(c,r);const u=a.kind===B.success?qe(n.raw,this.observationRetentionByToolId.get(i.toolName)):void 0;if(u){r.canonicalToolOutputs.set(i.toolCallId,u);const e=this.observationResultIds.get(i.toolCallId);void 0!==e&&e!==c.id&&this.ambiguousObservationCallIds.add(i.toolCallId),this.observationResultIds.set(i.toolCallId,this.ambiguousObservationCallIds.has(i.toolCallId)?void 0:c.id)}!0===o?.potentialSideEffect&&a.kind!==B.userRejected&&a.kind!==B.policyDenied&&a.kind!==B.invalidInput&&(r.hadPotentialSideEffects=!0),r.pendingToolCalls.delete(i.toolCallId),s.push({type:"tool-result",toolCallId:i.toolCallId,agentName:t?.agentName??i.toolName,toolName:t?.toolName??i.toolName,executionId:c.id,...void 0===c.appOutput?{}:{appOutput:e(c.appOutput)},outcome:a,display:l,output:l,isError:a.kind!==B.success}),r.aborted||r.abortController.signal.aborted||a.kind!==B.userRejected||(pe=nt(i.output));break}case"tool-error":{ke.end(i.toolCallId);const t=this.registry.resolve(i.toolName),o=rt(i.error),n=(o===B.invalidInput?J(i.error):void 0)??nt(i.error),a=r.pendingToolCalls.get(i.toolCallId)?.input??(p.isInstance(i.error)?i.error.toolInput:void 0),l=this.skillToolInputError(i.toolName,a)??U(o,n,{raw:i.error}),c=nt(l);i.toolName===this.skillToolId&&r.canonicalToolOutputs.set(i.toolCallId,l.model);const u=K({toolCallId:i.toolCallId,agentName:t?.agentName??i.toolName,toolName:t?.toolName??i.toolName,input:a,result:l});this.persistToolExecution(u,r),!0===r.pendingToolCalls.get(i.toolCallId)?.potentialSideEffect&&l.outcome.kind!==B.invalidInput&&(r.hadPotentialSideEffects=!0),r.pendingToolCalls.delete(i.toolCallId),s.push({type:"tool-result",toolCallId:i.toolCallId,agentName:t?.agentName??i.toolName,toolName:t?.toolName??i.toolName,executionId:u.id,...void 0===u.appOutput?{}:{appOutput:e(u.appOutput)},outcome:l.outcome,display:l.display,output:c,isError:!0});break}case"finish-step":{if(ke.clear(),void 0!==g&&void 0!==ue)break;const e=ct(i.usage);void 0!==e.inputTokens&&(re=e.inputTokens,q=$),ve+=1,ce=i.finishReason;const t=i.performance.outputTokensPerSecond??i.performance.effectiveOutputTokensPerSecond;void 0!==t&&Number.isFinite(t)&&(le=t),s.push({type:"step-finish",finishReason:i.finishReason,usage:e});break}case"finish":!ge&&me.length>0&&(he+=me,s.push({type:"text-delta",delta:me}),me=""),ne=ct(i.totalUsage);break;case"error":if(ke.clear(),this.isTurnAborted(r)||W(i.error)){r.aborted=!0,r.cancellationReason=ht(r.cancellationReason,i.error);break}ye=lt(i.error),de=i.error,fe=!0,ue=et(i.error)??tt(i.error);break;case"abort":ke.clear(),r.aborted=!0,r.cancellationReason=ht(r.cancellationReason,i.reason)}}}catch(e){this.isTurnAborted(r)||W(e)?(r.aborted=!0,r.cancellationReason=ht(r.cancellationReason,e)):(ye=lt(e),de=e,fe=!1,ue=tt(e))}finally{r.abortController.signal.removeEventListener("abort",xe),ke.dispose(),this.clearDebugTimer(Ie)}if(this.debug(s,"model","fullStream finished",m,{textChars:he.length}),void 0!==V){try{await it(ie.steps,r.abortController.signal)}catch{}if(this.isTurnAborted(r))return void this.persistCancelledTurn(s,r,b,m);if(r.pendingToolCalls.size>0)return this.persistFailedTurn(s,r,N,m),void s.push({type:"error",stage:"execute",message:"context_maintenance_unsettled_tools:输入已保存,请先核对未结算操作。"});const e=mt(Ye(r));this.messages.push(...e),e.length>0&&this.persistMessages(e,"raw_transcript"),Xe(r),b=this.messages.length,r.completedStepCount+=ve,void 0!==Y&&(D=void 0===D?Y:dt(D,Y),this.sessionUsage=dt(this.sessionUsage,Y)),this.toolCoordinator.finishTurn();const i=V;if(e.length>0){if(r.completedStepCount>=this.maxSteps)return void s.push({type:"message-finish",text:he,stoppedAtStepLimit:!0,sessionUsage:{...this.sessionUsage},...void 0===D?{}:{totalUsage:D},...void 0===re?{}:{contextInputTokens:re}});s.push({type:"message-start",messageId:t()});continue}if("shape_changed"===i.reason)continue;if(w||!0!==this.compaction?.enabled)return void s.push({type:"error",stage:"plan",message:`context_request_budget_unrecoverable:输入和已完成操作已保留;当前请求未通过预算检查(${i.reason},估算输入 ${Math.ceil(i.budget.calibratedInputEstimate)},输入上限 ${i.budget.availableInputCeiling??"未知"},最近实测 ${i.budget.latestMeasuredInput??"未知"})。可继续发送较小的新要求或手动压缩。`});w=!0,this.requestBudgets.beginMaintenance(i.budget,r.inputId);const n=void 0===i.budget.maintenanceTarget?void 0:Math.max(1,.5*i.budget.maintenanceTarget-(i.budget.calibratedInputEstimate-i.budget.messageTokens));let a=!1;try{a=await this.runCompaction(s,"auto",r,!1,n,(e,t)=>o({history:e,explicitSkill:A,capabilityReminder:L,...void 0===t?{}:{checkpointReminder:t},system:this.systemPrompt,tools:y,project:e=>this.projectModelMessages(e),...void 0===this.providerOptions?{}:{providerOptions:this.providerOptions}}).messages)}catch(e){if(this.isTurnAborted(r))throw e;this.debug(s,"compaction","summary failed; original context retained",m,{message:tt(e)})}if(I=a?void 0:i.budget,b=this.messages.length,this.isTurnAborted(r))return void this.persistPausedTurnCancellation(s,r,m);s.push({type:"message-start",messageId:t()});continue}if(void 0!==ue&&this.isTurnAborted(r))return void this.persistCancelledTurn(s,r,b,m);if(void 0!==ue&&!ye&&fe&&g?.isRecoverable(de)&&void 0!==v&&!r.userRejected&&void 0===pe&&void 0===O.message){f=de;try{await it(ie.steps,r.abortController.signal)}catch(e){if(r.abortController.signal.throwIfAborted(),!h.isInstance(e)&&e!==de)throw e}const e=mt(Ye(r)),t=new Map;for(const s of e)if("tool"===s.role)for(const e of s.content)"tool-result"===e.type&&t.set(e.toolCallId,(t.get(e.toolCallId)??0)+1);if([...this.uncoveredToolExecutions.values()].some(e=>{const s=t.get(e.toolCallId)??0;return t.set(e.toolCallId,s-1),0===s})||[...r.pendingToolCalls.values()].some(e=>this.toolCoordinator.hasExecutionStarted(e.executionOccurrence)))fe=!1,ue="网络中断且操作结果尚未完整结算;已停止自动恢复,请先核对结果。";else{if(this.toolCoordinator.finishTurn(),e.length>0&&(this.persistMessages(e,"raw_transcript"),this.messages.push(...e)),Xe(r),b=this.messages.length,this.persistRecoveryCancellations(s,r),b=this.messages.length,r.completedStepCount+=ve,void 0!==Y&&(D=void 0===D?Y:dt(D,Y),this.sessionUsage=dt(this.sessionUsage,Y)),r.completedStepCount>=this.maxSteps)return void s.push({type:"error",stage:"execute",message:"已达单轮最大工具步数;未完成的回复已丢弃,输入和已完成的操作已保留。"});const t=await v.attempt(de,r.abortController.signal,e=>s.push({type:"model-recovery",attempt:e}));if(t.recovered){f=void 0;continue}de=t.error,ue=tt(t.error)}}if(void 0!==ue){if(fe&&!ye&&(f=de),fe&&!ye&&g?.formatError&&(ue=et(de)??g.formatError(de)),ye&&void 0!==G&&(R.add(G.fingerprint),P=G),this.messages.splice(b),ye){const e=0===he.length&&!ge,t=e&&S<1,o=!(!t&&e)&&await this.recoverFromContextError(s,r);if(this.isTurnAborted(r))return void this.persistCancelledRecoveryTurn(s,r,N,m);if(e&&o&&t){S+=1;continue}const i=e?"":";本次尝试已有内容或操作开始执行,为避免重复执行,未自动重试";return this.persistContextFailure(s,r,N,he.length>0,m),void s.push({type:"error",stage:"execute",message:`${ue}${i}`})}return this.persistFailedTurn(s,r,N,m),void s.push({type:"error",stage:"execute",message:ue})}if(r.aborted||r.abortController.signal.aborted)return r.cancellationReason=ht(r.cancellationReason,r.abortController.signal.reason),void this.persistCancelledTurn(s,r,b,m);let Se;this.debug(s,"model","awaiting response messages",m);const we=this.scheduleDebug(s,"model","still awaiting response messages",m);try{const e=await ie.steps;Se=Je(r,e)}catch(e){if(this.clearDebugTimer(we),this.isTurnAborted(r)||W(e))return r.aborted=!0,r.cancellationReason=ht(r.cancellationReason,e),void this.persistCancelledTurn(s,r,b,m);const t=lt(e);if(t&&void 0!==G&&(P=G,R.add(G.fingerprint)),this.messages.splice(b),t){const t=0===he.length&&!ge,o=t&&S<1,i=!(!o&&t)&&await this.recoverFromContextError(s,r);if(this.isTurnAborted(r))return void this.persistCancelledRecoveryTurn(s,r,N,m);if(t&&i&&o){S+=1;continue}const n=t?"":";本次尝试已有内容或操作开始执行,为避免重复执行,未自动重试";return this.persistContextFailure(s,r,N,he.length>0,m),void s.push({type:"error",stage:"execute",message:`${tt(e)}${n}`})}return this.persistFailedTurn(s,r,N,m),void s.push({type:"error",stage:"execute",message:tt(e)})}finally{this.clearDebugTimer(we)}if(this.debug(s,"model","response messages ready",m,{responseMessages:Se.length}),this.isTurnAborted(r))return r.cancellationReason=ht(r.cancellationReason,r.abortController.signal.reason),void this.persistCancelledTurn(s,r,b,m);const Me=mt(Se);this.messages.push(...Me);const Ee=pe??O.message;if(void 0!==Ee){const e=0===he.length?Ee:`\n${Ee}`;he+=e,s.push({type:"text-delta",delta:e}),this.messages.push({role:"assistant",content:Ee})}this.debug(s,"persist","persisting messages",m,{appendedMessages:this.messages.length-b}),this.persistMessages(this.messages.slice(b),"raw_transcript"),Xe(r),b=this.messages.length,this.debug(s,"persist","messages persisted",m,{totalMessages:this.messages.length}),ne&&(D=void 0===D?ne:dt(D,ne),this.sessionUsage=dt(this.sessionUsage,ne));const Re=re;void 0!==Re&&(this.lastInputTokens=Re,this.measuredProjectedTokens=q??$,this.promptOverhead=Math.max(0,Re-this.measuredProjectedTokens-l)),r.completedStepCount+=ve;const Pe=r.completedStepCount>=this.maxSteps&&"tool-calls"===ce;if(s.push({type:"message-finish",text:he,...void 0===D?{}:{totalUsage:D},sessionUsage:{...this.sessionUsage},...void 0!==re?{contextInputTokens:re}:{},...void 0!==le?{outputTokensPerSecond:le}:{},...Pe?{stoppedAtStepLimit:!0}:{}}),!r.pausedForContextPressure||"tool-calls"!==ce||Pe||void 0!==Ee)return;if(r.pausedForContextPressure=!1,this.debug(s,"compaction","turn paused for context pressure",m,{continuations:r.contextPressureContinuations,pressureTokens:this.contextPressureTokens()}),this.isTurnAborted(r))return void this.persistPausedTurnCancellation(s,r,m);s.push({type:"message-start",messageId:t()})}}catch(e){if(this.isTurnAborted(r)||W(e))return r.aborted=!0,r.cancellationReason=ht(r.cancellationReason,r.abortController.signal.reason??e),void(void 0!==b?this.persistCancelledTurn(s,r,b,m):this.emitCancellation(s,r));void 0!==b&&this.messages.splice(b),this.debug(s,"turn","error",m,{message:tt(e)}),s.push({type:"error",stage:"execute",message:tt(e)})}finally{this.requestBudgets.abandonMaintenance(r.inputId),void 0!==y&&clearTimeout(y),this.toolCoordinator.finishTurn();try{g?.onTurnEnd?.(this.isTurnAborted(r)?void 0:f)}finally{this.activeTurn===r&&(this.activeTurn=void 0),s.close()}}}persistMessages(e,t){const s=[...this.uncoveredToolExecutions.keys()],o=0===s.length?void 0:{toolExecutionCoverage:{executionIds:s,representation:t}};this.onPersist?.(e,o),this.recordPersistedMessagesInMemory(e);for(const e of s)this.uncoveredToolExecutions.delete(e)}recordPersistedMessagesInMemory(e){if(void 0!==this.listPersistedTranscriptMessages)return;let t=(this.inMemoryTranscript.at(-1)?.sequence??-1)+1;const s=(new Date).toISOString();for(const o of e)ot(o)||(this.inMemoryTranscript.push({sequence:t,provenance:Re[0],createdAt:s,message:o}),t+=1)}reconcileUncoveredToolExecutionContext(){if(void 0!==this.recoverPersistedToolExecutionContext){const e=this.recoverPersistedToolExecutionContext();return this.messages.push(...e),this.recordPersistedMessagesInMemory(e),void this.uncoveredToolExecutions.clear()}const e=[...this.uncoveredToolExecutions.values()];if(0===e.length)return;const t=this.messages.length,s=ge(e);this.messages.push(s);try{this.persistMessages([s],"recovery_evidence")}catch(e){throw this.messages.splice(t),e}}persistContextFailure(e,t,s,o,i){if(!this.persistPendingToolCancellationsOrReport(e,t,"上下文溢出工具状态持久化失败"))return;const n=t.toolExecutions.some(e=>e.outcome.kind!==B.policyDenied&&e.outcome.kind!==B.userRejected&&e.outcome.kind!==B.invalidInput&&(e.outcome.kind!==B.cancelled||e.outcome.executionState!==F.notExecuted)),r=["本轮因上下文窗口溢出而中断,未自动重放。"];o&&r.push("本轮已产生部分文本,持久历史仅保留此中断标记。"),n&&r.push("本轮已有操作开始执行,部分结果可能已经生效且不会自动撤销,请先检查实际结果。");const a=[...this.uncoveredToolExecutions.values()];this.appendInterruptedTurnMessages(e,t,i,{rollbackTo:this.messages.length,messages:[...t.userMessagePersisted?[]:[s],...0===a.length?[]:[ge(a)],{role:"assistant",content:r.join("")}],debugLabel:"persisting context-overflow marker",debugDetails:{hadToolActivity:n,producedText:o},failureLabel:"上下文溢出记录持久化失败"})}persistFailedTurn(e,t,s,o){if(this.closed)return;const i=Ke(t);if(!(i.length>0||t.toolExecutions.length>0||t.pendingToolCalls.size>0))return;const n=Oe(mt(Ye(t))).messages;this.persistPendingToolCancellationsOrReport(e,t,"取消工具账本持久化失败")&&this.appendInterruptedTurnMessages(e,t,o,{rollbackTo:this.messages.length,messages:[...t.userMessagePersisted?[]:[s],...n,me({context:this.failedTurnContextMessage(t),completedMessages:i,toolExecutions:t.toolExecutions}),{role:"assistant",content:this.failedTurnDisplayMessage(t)}],debugLabel:"persisting failed turn",failureLabel:"失败状态持久化失败"})}failedTurnContextMessage(e){const t=this.cancellationActivity(e).execSessionIds;return`本轮因运行错误中断,未自动重试。${t.length>0?`本轮后台任务编号: ${t.join(", ")}。`:""}已完成的步骤和工具记录仍然有效,不要自动重复 outcome=success 的操作。${ze}`}failedTurnDisplayMessage(e){const t=this.cancellationActivity(e);return`本轮因运行错误而中断,未自动重试。之前的对话和已完成进度会保留。${t.hadPotentialSideEffects?"部分操作可能已经生效且不会自动撤销,请先检查实际结果,再决定是否继续。":t.hadInFlightWork?"刚才的任务结果尚未确认,请先检查后再继续。":"你可以继续输入或重试。"}`}appendInterruptedTurnMessages(e,t,s,o){if(t.pendingToolCalls.size>0)return e.push({type:"error",stage:"execute",message:`${o.failureLabel}: 存在未写入账本的待处理工具调用,已拒绝持久化中断记录`}),!1;this.messages.push(...o.messages),this.debug(e,"persist",o.debugLabel,s,{appendedMessages:this.messages.length-o.rollbackTo,...o.debugDetails});try{return this.persistMessages(this.messages.slice(o.rollbackTo),"recovery_evidence"),!0}catch(t){return this.messages.splice(o.rollbackTo),e.push({type:"error",stage:"execute",message:`${o.failureLabel}: ${tt(t)}`}),!1}}persistToolExecution(e,t){this.onToolExecution?.(e),this.inMemoryToolExecutions.push(e),t.toolExecutions.push(e),this.uncoveredToolExecutions.set(e.id,e)}interactionDeadlineMs(e,t){const s=void 0===e.expiresAt?Number.POSITIVE_INFINITY:Date.parse(e.expiresAt);return Math.min(t+Be,Number.isFinite(s)?s:Number.POSITIVE_INFINITY)}requestApproval(e){const s=t(),o=this.gate.request(s);if(void 0===this.emit)return this.gate.resolve(s,{approved:!1,reason:"approval event could not be delivered"}),o;const i=void 0===this.activeTurn?void 0:new Date(this.interactionDeadlineMs(this.activeTurn,Date.now())).toISOString();return this.emit({type:"confirmation-required",approvalId:s,agentName:e.agentName,toolName:e.toolName,input:e.input,...void 0!==i?{expiresAt:i}:{},...e.reason?{reason:e.reason}:{},...void 0!==e.explanation?{explanation:e.explanation}:{},...void 0!==e.sessionGrantLabel?{sessionGrantLabel:e.sessionGrantLabel}:{},...void 0!==e.diff?{diff:e.diff}:{},...void 0!==e.fullDiff?{fullDiff:e.fullDiff}:{}}),o}approve(e,t){return this.gate.resolve(e,{approved:!0,...void 0!==t?{scope:t}:{}})}reject(e,t){const s=this.gate.resolve(e,{approved:!1,...t?{reason:t}:{}});return s&&void 0!==this.activeTurn&&(this.activeTurn.userRejected=!0),s}getMessages(){return he(ve(this.messages))}getToolExecutions(e={},t=!1){const s=this.listPersistedToolExecutions?this.listPersistedToolExecutions(e):this.inMemoryToolExecutions.map((e,t)=>({...e,sequence:t})).filter(t=>t.sequence>(e.afterSequence??-1)&&(void 0===e.toolCallId||t.toolCallId===e.toolCallId)).slice(0,e.limit??100);return t?s:s.map(e=>({...Y(e),sequence:e.sequence}))}getToolExecution(e,t=!1){const s=this.getPersistedToolExecution?.(e),o=s??(()=>{const t=this.inMemoryToolExecutions.findIndex(t=>t.id===e),s=this.inMemoryToolExecutions[t];return s?{...s,sequence:t}:void 0})();return!o||t?o:{...Y(o),sequence:o.sequence}}getCapabilityManifest(){return structuredClone(this.capabilityManifest)}getCapabilityTurnContext(){return this.lastCapabilityTurnContext?structuredClone(this.lastCapabilityTurnContext):void 0}getContextWindow(){return this.contextWindow}getRequestBudgetState(){return this.requestBudgets.view()}getSessionUsage(){return{...this.sessionUsage}}getSkillSummaries(){return this.skillSummaries}setProviderOptions(e){this.onProviderOptionsChange?.(e),this.providerOptions=e}canSwitchModel(){return void 0===this.activeTurn}switchModel(e){if(!this.canSwitchModel())throw new Error("会话正在生成回复,稍后再切换模型");this.model=e.model,this.modelRecovery=e.modelRecovery,this.requestBudgets=new r,this.contextWindowSource=e.contextWindowSource,this.contextWindow=e.contextWindow,this.providerOptions=e.providerOptions,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.lastInputTokens=void 0,this.measuredProjectedTokens=void 0,this.promptOverhead=void 0,void 0!==e.toolSchemaPolicy&&(this.toolSchemaPolicy=e.toolSchemaPolicy,this.applyToolSchemaPolicy()&&this.refreshCapabilityManifest())}modelTools(){if(0===this.excludedToolIds.size)return this.tools;const e=this.excludedToolIds;return Object.fromEntries(Object.entries(this.tools).filter(([t])=>!e.has(t)))}recordToolSchemaIssues(e){for(const[t,s]of Object.entries(e))this.agentToolSchemaIssues.set(t,s)}applyToolSchemaPolicy(){const e=this.toolSchemaPolicy,t=new Set;if(e)for(const[s,o]of this.agentToolSchemaIssues)e(o)||t.add(s);const s=this.excludedToolIds,o=t.size!==s.size||[...t].some(e=>!s.has(e));for(const e of t)if(!s.has(e)){const t=this.registry.resolve(e);this.onToolExcluded?.({toolId:e,agentName:t?.agentName??"",toolName:t?.toolName??e,issues:this.agentToolSchemaIssues.get(e)??[]})}return this.excludedToolIds=t,o}stopOnContextPressure(e,t,s,o=()=>!0){return({steps:i})=>{const n=this.compaction,r=i.at(-1);if(void 0===n||!n.enabled||void 0===this.contextWindow||void 0===r||"tool-calls"!==r.finishReason||i.length<2&&this.messages.length<2||r.toolResults.some(e=>G(e.output).kind===B.userRejected))return!1;const a=ct(r.usage),l=se(this.projectModelMessages([...this.messages,...Je(e,i)])),c=s?.()??(void 0===a.inputTokens?this.promptOverheadTokens()+l:Math.max(0,a.inputTokens+l-t()));return!(c/this.contextWindow<n.threshold||!o(c))&&(e.pausedForContextPressure=!0,!0)}}contextPressureTokens(e){const t=void 0===e?0:se([{role:"user",content:e}]),s=se(this.projectModelMessages(this.messages));return void 0!==this.lastInputTokens&&void 0!==this.measuredProjectedTokens?Math.max(0,this.lastInputTokens+s-this.measuredProjectedTokens+t):this.promptOverheadTokens()+s+t}observationResultId(e){if(this.observationResultIds.has(e))return this.observationResultIds.get(e);const t=this.listPersistedToolExecutions?.({toolCallId:e,limit:2})??[];t.length>1&&this.ambiguousObservationCallIds.add(e);const s=1===t.length?t[0]?.id:void 0;return this.observationResultIds.set(e,s),s}readObservation(e){const t=this.getPersistedToolExecution?.(e.resultId)??(()=>{const t=this.inMemoryToolExecutions.findIndex(t=>t.id===e.resultId),s=this.inMemoryToolExecutions[t];return s?{...s,sequence:t}:void 0})();if(!t)throw new Error("当前会话中没有这个工具结果");const s=[...this.observationRetentionByToolId].find(([e])=>{const s=this.registry.resolve(e);return s?.agentName===t.agentName&&s.toolName===t.toolName})?.[1];if(!s)throw new Error("该结果不是可回查的浏览器观察");return je(e,t,[...this.messages,...this.activeTurn?Ye(this.activeTurn):[]],s,this.observationResultId(t.toolCallId)===t.id)}projectModelMessages(e){return $e(e,{declarations:this.observationRetentionByToolId,resultId:e=>this.observationResultId(e),...this.observationRecallToolId?{recallToolId:this.observationRecallToolId}:{}})}promptOverheadTokens(){const e=this.currentCheckpointReminder(Ce(this.capabilityManifest,be.transcriptRead));return(this.promptOverhead??0)+(void 0===e?0:oe(e))}currentCheckpointReminder(e){return void 0===this.compactionCheckpoint?void 0:we(this.compactionCheckpoint,this.sessionManagerInstanceId,e)}persistPausedTurnCancellation(e,t,s){if(!this.persistPendingToolCancellationsOrReport(e,t,"取消工具账本持久化失败"))return t.cancellationPersistenceAttempted=!0,void this.emitCancellation(e,t);if(!t.cancellationPersistenceAttempted&&!this.closed){t.cancellationPersistenceAttempted=!0,t.cancellationPersisted=!0;const o=this.cancellationRecordMessages(t,Ke(t));t.cancellationPersisted=this.appendInterruptedTurnMessages(e,t,s,{rollbackTo:this.messages.length,messages:o,debugLabel:"persisting paused turn cancellation",failureLabel:"取消状态持久化失败"})}this.emitCancellation(e,t)}compactionTargetTokens(e){const t=this.compaction;if(void 0===t||void 0===this.contextWindow)return;const s=void 0===e?0:se([{role:"user",content:e}]);return Math.max(1,Math.floor(this.contextWindow*t.threshold)-this.promptOverheadTokens()-s)}listCompactionTranscriptEvidence(){const e=this.listPersistedTranscriptMessages,t=e=>({...e,message:le(e.message,this.getInputSkillCheckpoint?.(e.sequence)??this.inputSkillCheckpoints.get(e.sequence))});if(void 0===e)return this.inMemoryTranscript.map(t);const s=[];let o=-1;for(;;){const i=e({afterSequence:o,limit:500});s.push(...i.map(t));const n=i.at(-1)?.sequence;if(i.length<500||void 0===n||n<=o)break;o=n}return s}listCompactionToolEvidence(){const e=this.listPersistedToolExecutions;if(void 0===e)return this.inMemoryToolExecutions.map((e,t)=>({...e,sequence:t}));const t=[];let s=-1;for(;;){const o=e({afterSequence:s,limit:500});t.push(...o);const i=o.at(-1)?.sequence;if(o.length<500||void 0===i||i<=s)break;s=i}return t}async runCompactionTurn(e,t,s){try{this.reconcileUncoveredToolExecutionContext(),await this.runCompaction(e,s,t,!0,this.compactionTargetTokens())}catch(s){this.isTurnAborted(t)?this.emitCancellation(e,t):e.push({type:"error",stage:"plan",message:tt(s)})}finally{this.activeTurn===t&&(this.activeTurn=void 0),e.close()}}async runCompaction(e,t,s,i,n,r){const a=Date.now(),l=this.lastInputTokens,c=this.compaction,u=c?.strategy??"summarize";e.push({type:"compaction-start",reason:t});const d=s=>(e.push({type:"context-compacted",...void 0===l?{}:{beforeInputTokens:l},reason:t,strategy:u,removed:0,kept:this.messages.length,...s?{failure:s}:"manual"===t?{recoveryNotice:"当前内容未产生可用的压缩,已保留原上下文。"}:{}}),!1);if(this.isTurnAborted(s))return i&&s&&this.emitCancellation(e,s),d();if(!c)return d();try{const p=[...this.messages],h=this.compactionCheckpoint,m=Ce(this.capabilityManifest,be.transcriptRead),g=void 0===h?void 0:3===h.version?h.taskSummary:we(h,this.sessionManagerInstanceId,m),v=await te({messages:p,strategy:u,keepRecentTurns:c.keepRecentTurns,keepRecentTokens:c.keepRecentTokens,model:this.model,...void 0===g?{}:{previousSummary:g},...void 0===n?{}:{targetTokens:n},...void 0===this.contextWindow?{}:{contextWindow:this.contextWindow},...void 0===c.timeoutMs?{}:{timeoutMs:c.timeoutMs},...void 0===c.maxOutputTokens?{}:{maxOutputTokens:c.maxOutputTokens},...void 0===this.structuredOutputReasoning?{}:{structuredOutputReasoning:this.structuredOutputReasoning},...void 0===this.structuredOutputProviderOptions?{}:{structuredOutputProviderOptions:this.structuredOutputProviderOptions},...void 0===s?{}:{abortSignal:s.abortController.signal}});if(this.isTurnAborted(s))return i&&s&&this.emitCancellation(e,s),d();if(0===v.removed)return d();const f=v.summary??("truncate"===u?g??"Earlier messages were archived. Consult the original transcript for historical details.":void 0);if(void 0===f||0===f.trim().length)return d();if(Oe(v.messages).status===Pe.repaired)return d();const b=this.currentCheckpointReminder(m),y=(e,t)=>void 0===r?this.requestBudgets.projectedMessageTokens(o({history:e,explicitSkill:{skillNames:[],userPrompt:"",modelUserContent:""},capabilityReminder:"",...void 0===t?{}:{checkpointReminder:t},system:this.systemPrompt,tools:this.modelTools(),project:e=>this.projectModelMessages(e)}).messages):this.requestBudgets.projectedMessageTokens(r(e,t)),T=y(p,b),C=new Error("compaction_candidate_did_not_shrink");let I=T;const k=e=>{const t=we(e,this.sessionManagerInstanceId,m);if(I=y(v.messages,t),I>=T)throw C};let x;try{if(this.commitPersistedCompaction)x=this.commitPersistedCompaction({messages:v.messages,expectedActiveMessages:p,expectedLatestCheckpointId:h?.id,summary:f,validateCheckpoint:k});else{const e=this.listCompactionTranscriptEvidence(),t=this.listCompactionToolEvidence(),s=Ee({summary:f,generation:(h?.generation??0)+1,...h?{previousCheckpointId:h.id}:{},transcript:{messages:{fromSequenceExclusive:-1,throughSequence:e.at(-1)?.sequence??h?.transcript.messages.throughSequence??-1},toolExecutions:{fromSequenceExclusive:-1,throughSequence:t.at(-1)?.sequence??h?.transcript.toolExecutions.throughSequence??-1},completeness:h?.transcript.completeness??"complete"},toolState:Me(e.map(e=>e.message),t)});k(s),this.onReplace?.(v.messages),x=s}}catch(e){if(e===C)return d();throw e}return this.messages.splice(0,this.messages.length,...v.messages),this.compactionCheckpoint=x,this.lastInputTokens=void 0,this.measuredProjectedTokens=void 0,e.push({type:"context-compacted",...void 0===l?{}:{beforeInputTokens:l},reason:t,strategy:u,removed:v.removed,kept:v.kept,checkpointId:x.id,checkpointGeneration:x.generation,checkpointSummaryStatus:"summarize"===u?"valid":"skipped"}),this.debug(e,"compaction","task summary committed",a,{removed:v.removed,kept:v.kept,beforeEstimatedTokens:T,afterEstimatedTokens:I}),!0}catch(e){throw d(this.isTurnAborted(s)?void 0:e instanceof ee?{reason:f.timeout,timeoutMs:e.timeoutMs}:{reason:f.error}),e}}async recoverFromContextError(e,t){if(!this.compaction?.enabled)return!1;try{return await this.runCompaction(e,"auto",t,!1,this.compactionTargetTokens())}catch(s){return this.isTurnAborted(t)||e.push({type:"error",stage:"plan",message:tt(s)}),!1}}isTurnAborted(e){return!0===e?.aborted||!0===e?.abortController.signal.aborted}execSessionIds(e){return[...e.execSessionIds].sort((e,t)=>e-t)}activeExecSessionIds(e){return this.execSessionIds(e).filter(e=>{const t=this.sessionManager?.get(e);return void 0!==t&&!O(t.state)})}interruptExecSessions(e){const t=this.execSessionIds(e);0!==t.length&&this.sessionManager?.interrupt(t).catch(e=>{process.stderr.write(`roll chat: 中断后台会话失败: ${tt(e)}\n`)})}abandonTurn(e){this.closed||this.activeTurn!==e||e.abortController.signal.aborted||(this.captureCancellationActivity(e),e.aborted=!0,e.cancellationReason??=j.runtime,this.gate.abortAll("本轮事件流已停止"),this.userInputInteractions.cancelAll("本轮事件流已停止"),this.interruptExecSessions(e),e.abortController.abort(N))}currentCancellationActivity(e){const t=this.activeExecSessionIds(e),s=[...e.pendingToolCalls.values()].filter(e=>this.toolCoordinator.hasExecutionStarted(e.executionOccurrence));return{execSessionIds:t,hadCompletedProgress:e.toolExecutions.length>0||e.completedStepResponses.size>0,hadInFlightWork:s.length>0||t.length>0,hadPotentialSideEffects:e.hadPotentialSideEffects||s.some(e=>e.potentialSideEffect)}}captureCancellationActivity(e){e.cancellationActivity??=this.currentCancellationActivity(e)}cancellationActivity(e){return e.cancellationActivity??this.currentCancellationActivity(e)}cancellationDisplayMessage(e){const t=e.cancellationReason??j.runtime,s=this.cancellationActivity(e);if(e.cancellationPersistenceAttempted&&!e.cancellationPersisted){const o=s.hadPotentialSideEffects?"部分操作可能已经执行,请先检查结果后再继续。":s.hadInFlightWork?"刚才的任务结果尚未确认,请先检查后再继续。":"请重新输入需要继续的内容。",i=e.userMessagePersisted?"本轮输入已保存,但进度或中断记录未能保存。":"刚才的对话和进度未能保存。";return t===j.timeout?`本轮等待时间过长,已自动停止。${i}${o}`:t===j.runtime?`本轮因运行异常而中断。${i}${o}`:`已停止本轮。${i}${o}`}const o=s.execSessionIds,i=Ce(this.capabilityManifest,be.sessionList);switch(t){case j.user:return s.hadInFlightWork?s.hadPotentialSideEffects?"已停止本轮操作。正在进行的任务也已请求停止。之前的对话和已完成进度会保留;部分已经完成的操作不会自动撤销,请检查结果。":"已停止本轮操作。正在进行的任务也已请求停止。之前的对话和已完成进度会保留。":s.hadCompletedProgress?s.hadPotentialSideEffects?"已停止本轮回复。之前的对话和已完成进度会保留;部分已经完成的操作不会自动撤销,请检查结果。":"已停止本轮回复。之前的对话和已完成进度会保留,你可以继续输入。":"已停止本轮回复。之前的对话会保留,你可以继续输入。";case j.timeout:return 0===o.length?"本轮等待时间过长,已自动停止。之前的对话和已完成进度会保留,你可以继续输入或重试。":Ie(this.capabilityManifest.lifecycle.hostMode)?"本轮等待时间过长,已自动停止。正在进行的任务会随本次命令结束而停止,之后无法继续查看;请先确认实际结果,再决定是否重试。":i?`本轮等待时间过长,但任务仍在运行(任务 #${o.join(", #")})。你可以在下一条消息中继续查看进度;确认结果前请勿重复执行。`:"本轮等待时间过长。任务可能仍在运行,但 Roll 暂时无法继续查看进度;请先确认实际结果,再决定是否重试。";case j.runtime:return s.hadInFlightWork?"本轮因运行异常而中断。正在进行的任务已请求停止,最终结果尚未确认;请检查结果后再继续。":s.hadPotentialSideEffects?"本轮因运行异常而中断。之前的对话和已完成进度会保留;部分已经完成的操作不会自动撤销,请检查结果后再继续。":"本轮因运行异常而中断。之前的对话会保留,你可以重试。"}}cancellationContextMessage(e){const t=e.cancellationReason??j.runtime,s=this.cancellationActivity(e).execSessionIds,o=s.length>0?`本轮后台任务编号: ${s.join(", ")}。`:"",i=Ce(this.capabilityManifest,be.sessionList),n=ze;switch(t){case j.user:return`用户主动停止了本轮。${o}这些任务已收到停止请求;已完成的步骤和工具记录仍然有效,不要自动重复 outcome=success 的操作。${n}`;case j.timeout:{const e=void 0!==this.turnTimeoutMs?`(${String(this.turnTimeoutMs)}ms)`:"";return 0===s.length?`本轮因超时${e}停止。已完成的步骤和工具记录仍然有效。${n}`:Ie(this.capabilityManifest.lifecycle.hostMode)?`本轮因超时${e}停止。${o}当前 one-shot 进程结束时会清理这些任务,后续 CLI 进程无法恢复。${n}`:i?`本轮因超时${e}停止,但后台任务仍在当前进程运行。${o}若且仅若最新用户明确要求继续或核对上一任务,可用 ${i} 找回并查看。${n}`:`本轮因超时${e}停止,但后台任务可能仍在运行。${o}当前没有可用的任务列表工具,不能安全恢复查看。${n}`}case j.runtime:return`本轮因运行异常中断。${o}已完成的步骤和工具记录仍然有效。${n}`}}emitCancellation(e,t){if(t.cancellationEventEmitted)return;t.cancellationReason??=j.runtime,t.cancellationEventEmitted=!0;const s=this.cancellationActivity(t).execSessionIds;e.push({type:"turn-cancelled",reason:t.cancellationReason,message:this.cancellationDisplayMessage(t),...s.length>0?{execSessionIds:s}:{}})}persistCancelledRecoveryTurn(e,t,s,o){const i=this.messages.length;t.userMessagePersisted||this.messages.push(s),this.persistCancelledTurn(e,t,i,o,Ue.ledgerOnly)}persistCancelledTurn(e,t,s,o,i=Ue.keepRaw){if(!this.persistPendingToolCancellationsOrReport(e,t,"取消工具账本持久化失败"))return this.messages.splice(s),t.cancellationPersistenceAttempted=!0,void this.emitCancellation(e,t);if(this.closed)return this.messages.splice(s),t.cancellationPersistenceAttempted=!0,void this.emitCancellation(e,t);if(!t.cancellationPersistenceAttempted){t.cancellationPersistenceAttempted=!0,this.messages.splice(s);const n=i===Ue.keepRaw,r=n?Oe(mt(Ye(t))).messages:[],a=n?Ke(t):Qe(t);t.cancellationPersisted=!0;const l=this.cancellationRecordMessages(t,a);t.cancellationPersisted=this.appendInterruptedTurnMessages(e,t,o,{rollbackTo:s,messages:[...r,...l],debugLabel:"persisting cancelled turn",failureLabel:"取消状态持久化失败"})}this.emitCancellation(e,t)}cancellationRecordMessages(e,t){return[me({context:this.cancellationContextMessage(e),completedMessages:t,toolExecutions:e.toolExecutions}),L(this.cancellationDisplayMessage(e),e.cancellationReason??j.runtime)]}persistPendingToolCancellationsOrReport(e,t,s){this.captureCancellationActivity(t);try{return this.persistPendingToolCancellations(e,t),!0}catch(t){return e.push({type:"error",stage:"execute",message:`${s}: ${tt(t)}`}),!1}}persistRecoveryCancellations(e,t){const s=[];for(const o of t.pendingToolCalls.values()){const i=_({kind:B.cancelled,reason:j.runtime,executionState:F.notExecuted},"模型连接中断,本工具调用确定未执行;重新生成的调用仍需正常校验与审批。"),n=K({toolCallId:o.toolCallId,agentName:o.agentName,toolName:o.toolName,input:o.input,result:i});this.persistToolExecution(n,t),e.push({type:"tool-result",toolCallId:o.toolCallId,agentName:o.agentName,toolName:o.toolName,executionId:n.id,outcome:i.outcome,display:i.display,output:i.display,isError:!0});const r=`${o.agentName}__${o.toolName}`;s.push({role:"assistant",content:[{type:"tool-call",toolCallId:o.toolCallId,toolName:r,input:o.input}]},{role:"tool",content:[{type:"tool-result",toolCallId:o.toolCallId,toolName:r,output:i.model}]}),t.pendingToolCalls.delete(o.toolCallId)}s.length>0&&(this.persistMessages(s,"raw_transcript"),this.messages.push(...s))}persistPendingToolCancellations(e,t){const s=t.cancellationReason??j.runtime;for(const o of t.pendingToolCalls.values()){const i=this.toolCoordinator.hasExecutionStarted(o.executionOccurrence)?F.outcomeUnknown:F.notExecuted,n=i===F.notExecuted?`工具调用在开始执行前因本轮 ${s} 中断而取消;确定未执行`:`工具调用已开始,因本轮 ${s} 中断而取消;最终结果尚未确认`,r=_({kind:B.cancelled,reason:s,executionState:i},n,{raw:{cancellationReason:s,executionState:i,abortReason:tt(t.abortController.signal.reason)}}),a=K({toolCallId:o.toolCallId,agentName:o.agentName,toolName:o.toolName,input:o.input,result:r});this.persistToolExecution(a,t),e.push({type:"tool-result",toolCallId:o.toolCallId,agentName:o.agentName,toolName:o.toolName,executionId:a.id,outcome:r.outcome,display:r.display,output:r.display,isError:!0}),t.pendingToolCalls.delete(o.toolCallId)}}cancel(){const e=this.activeTurn;return!!e&&(this.captureCancellationActivity(e),e.aborted=!0,e.cancellationReason=j.user,this.gate.abortAll("用户取消本轮"),this.userInputInteractions.cancelAll("用户取消本轮"),this.interruptExecSessions(e),e.abortController.abort($),!0)}close(){if(void 0!==this.closePromise)return this.closePromise;this.closed=!0;const e=this.activeTurn;return e&&(this.captureCancellationActivity(e),e.aborted=!0,e.cancellationReason??=j.runtime,this.gate.abortAll(),this.userInputInteractions.cancelAll("Runtime 正在关闭"),e.abortController.abort(N)),this.closePromise=(async()=>{const e=(this.sessionManager?.close()??Promise.resolve([])).then(e=>{for(const t of e)void 0!==t.cleanupError&&process.stderr.write(`roll chat: 后台会话 ${String(t.sessionId)} 清理失败: ${t.cleanupError}\n`)},e=>{process.stderr.write(`roll chat: 会话 ${this.id} 后台清理失败: ${tt(e)}\n`)});await s(e,Fe)||process.stderr.write(`roll chat: 会话 ${this.id} 在 ${String(Fe)}ms 内未完成全部关闭步骤\n`);try{this.onClose?.()}catch(e){process.stderr.write(`roll chat: 会话 ${this.id} 关闭回调失败: ${tt(e)}\n`)}})(),this.closePromise}abort(){this.close().catch(e=>{process.stderr.write(`roll chat: 会话 ${this.id} 关闭失败: ${tt(e)}\n`)})}debug(e,t,s,o,i){this.debugEvents&&e.push({type:"debug",stage:t,message:s,...void 0!==o?{elapsedMs:Date.now()-o}:{},...void 0!==i?{data:i}:{}})}scheduleDebug(e,t,s,o,i){if(this.debugEvents)return setTimeout(()=>{this.debug(e,t,s,o,i)},5e3)}clearDebugTimer(e){void 0!==e&&clearTimeout(e)}}
@@ -33,6 +33,7 @@ export interface ConversationEngineOptions {
33
33
  readonly maxSteps?: number;
34
34
  readonly providerOptions?: SharedV4ProviderOptions;
35
35
  readonly modelRecovery?: AgentSessionOptions["modelRecovery"];
36
+ readonly resolveReasoningPresentation?: AgentSessionOptions["resolveReasoningPresentation"];
36
37
  readonly structuredOutputProviderOptions?: SharedV4ProviderOptions;
37
38
  readonly structuredOutputReasoning?: NonNullable<LanguageModelV4CallOptions["reasoning"]>;
38
39
  readonly debugEvents?: boolean;
@@ -90,6 +91,7 @@ export declare class ConversationEngine {
90
91
  private readonly maxSteps;
91
92
  private providerOptions;
92
93
  private modelRecovery;
94
+ private readonly resolveReasoningPresentation;
93
95
  private modelOverride;
94
96
  private modelName;
95
97
  private provider;
@@ -1 +1 @@
1
- import{randomUUID as e}from"node:crypto";import{AgentSession as s}from"./agent-session.js";import{resolveModelContextWindow as t}from"./context-window.js";import{createDefaultModelCatalog as o}from"./model-catalog-default.js";import{createWorkspaceInstructionsSource as i,parseWorkspaceInstructionsSetting as r}from"./workspace-instructions.js";import{CAPABILITY_HOST_MODES as n,shouldOfferAgentInstall as l,shouldOfferScheduleCreate as a}from"./capability-manifest.js";import{}from"../tool-bridge/bash-tool.js";import{unknownCommandClassifier as h}from"../types/command-classification.js";import{resolveShellProfile as c}from"../bash/profile.js";import{inspectGitVcsContext as d}from"./vcs-context.js";import{createToolLedgerGapRecoveryMessage as p}from"./cancelled-turn-recovery.js";const u="ConversationEngine is closing",m=e=>0===e.length;export function buildSessionExecSettings(e){const s=e.settings.shell;return{workdir:process.cwd(),profile:e.profile,maxSessions:s.session.maxSessions,defaultYieldMs:s.session.defaultYieldMs,maxOutputTokens:s.session.maxOutputTokens,bufferCapacity:s.maxCaptureBytes,env:e.env,...e.onCommandSpawn?{onCommandSpawn:e.onCommandSpawn}:{}}}export function buildSessionBashSettings(e){const s=e.settings.shell;return{workdir:process.cwd(),defaultTimeoutMs:s.defaultTimeoutMs,maxTimeoutMs:s.maxTimeoutMs,turnTimeoutMs:e.settings.turnTimeoutMs,maxCaptureBytes:s.maxCaptureBytes,maxModelOutputChars:s.maxModelOutputChars,profile:e.profile,env:e.env,...e.onCommandSpawn?{onCommandSpawn:e.onCommandSpawn}:{}}}function v(){return new Error(u)}function g(e){if(null===e.workspaceInstructions)return;if(void 0!==e.workspaceInstructions)return e.workspaceInstructions;const s=process.cwd();return i({cwd:s,setting:r(e.settings.instructions,s),...e.onWorkspaceInstructionsIssue?{onIssue:e.onWorkspaceInstructionsIssue}:{}})}export class ConversationEngine{settings;agentHost;store;policy;fileToolsEnabled;maxSteps;providerOptions;modelRecovery;modelOverride;modelName;provider;toolSchemaPolicy;switchingProviderName;modelCatalog;structuredOutputProviderOptions;structuredOutputReasoning;debugEvents;explicitModel;explicitSources;explicitSkillLibrary;workspaceInstructions;onAgentBootstrapIssue;hostMode;scheduleTools;resolveDynamicCapabilityContext;sessionExecEnabled;explicitShellProfile;resolveShellProfileFn;inspectVcsContext;shellEnv;onShellCommandSpawn;ready;refreshChain=Promise.resolve();resolvedCatalog=[];pendingInstalls=new Set;shellProfileResolution;shellUnsupportedWarned=!1;liveSessions=new Map;shutdownController=new AbortController;disposePromise;closing=!1;constructor(e){if(!e.model)throw new Error("ConversationEngine requires a model supplied by its host");if(void 0!==e.agentHost&&void 0!==e.sources)throw new Error("ConversationEngine accepts either sources or agentHost, not both");this.settings=e.settings,this.agentHost=e.agentHost,this.provider=e.provider,this.modelName=e.modelName,this.toolSchemaPolicy=e.toolSchemaPolicy??m,this.store=e.store,this.modelCatalog=e.modelCatalog??o(),this.policy=e.policy,this.fileToolsEnabled=e.fileToolsEnabled??!0,this.maxSteps=e.maxSteps??e.settings.maxSteps,this.providerOptions=e.providerOptions,this.modelRecovery=e.modelRecovery,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.debugEvents=e.debugEvents??!1,this.hostMode=e.hostMode??n.embedded,this.scheduleTools=e.scheduleTools??void 0,this.resolveDynamicCapabilityContext=e.resolveDynamicCapabilityContext,this.sessionExecEnabled=e.sessionExecEnabled??!0,this.explicitShellProfile=e.shellProfile,this.resolveShellProfileFn=e.resolveShellProfileFn??c,this.explicitModel=e.model,this.explicitSources=e.sources,this.explicitSkillLibrary=e.skillLibrary,this.workspaceInstructions=g(e),this.onAgentBootstrapIssue=e.onAgentBootstrapIssue,this.inspectVcsContext=e.inspectVcsContext??d,this.shellEnv={...e.shellEnv??process.env},this.onShellCommandSpawn=e.onShellCommandSpawn}async createSession(s={}){this.assertAcceptingSessions();const t=await this.ensureReady();this.assertAcceptingSessions();const o=this.store?this.store.createThread({...void 0===s.id?{}:{id:s.id},...void 0===s.origin?{}:{origin:s.origin},...s.title?{title:s.title}:{},model:this.resolveModelName()}):s.id??e();return this.buildSession(t,o,[])}async resumeSession(e){if(this.assertAcceptingSessions(),!this.store)throw new Error("resumeSession requires a ThreadStore");if("scheduled"===this.store.getThread(e)?.origin.kind)throw new Error("定时执行会话是只读记录;请基于该次运行创建新对话");const s=this.liveSessions.get(e);if(void 0!==s)return s;if(!this.store.hasThread(e))throw new Error(`Thread "${e}" 不存在`);const t=await this.ensureReady();this.assertAcceptingSessions();const o=this.liveSessions.get(e);if(void 0!==o)return o;this.recoverUncoveredToolExecutionContext(e);const i=this.store.loadSessionState(e);return this.buildSession(t,e,i.messages,i.checkpoint)}async forkSession(e,s={}){if(this.assertAcceptingSessions(),!this.store)throw new Error("forkSession requires a ThreadStore");const t=await this.ensureReady();this.assertAcceptingSessions();const o=this.store.forkSnapshot(e,{...s,model:this.resolveModelName()});try{this.recoverUncoveredToolExecutionContext(o);const e=this.store.loadSessionState(o);return this.buildSession(t,o,e.messages,e.checkpoint)}catch(e){throw this.store.deleteThread(o),e}}assertAcceptingSessions(){if(this.closing)throw v()}resolveRuntimeShellProfile(){if(!this.settings.shell.enabled)return;if(void 0!==this.explicitShellProfile)return this.explicitShellProfile??void 0;void 0===this.shellProfileResolution&&(this.shellProfileResolution=this.resolveShellProfileFn({platform:process.platform,env:this.shellEnv}));const e=this.shellProfileResolution;if(e.supported)return e.profile;if(!this.shellUnsupportedWarned){this.shellUnsupportedWarned=!0;const s="pwsh-version-unsupported"===e.reason?"检测到的 pwsh 版本低于 7":"未检测到 PowerShell 7 (pwsh)";process.stderr.write(`roll chat: ${s},Windows 原生 shell 工具已跳过注册;可运行 winget install Microsoft.PowerShell\n`)}}resolveShellSettings(e){return buildSessionBashSettings({settings:this.settings,profile:e,env:this.shellEnv,...this.onShellCommandSpawn?{onCommandSpawn:this.onShellCommandSpawn}:{}})}resolveSessionExecSettings(e){if(!this.sessionExecEnabled)return;const s=this.settings.shell;return s.enabled&&s.session.enabled&&e.supportsSessionExec?buildSessionExecSettings({settings:this.settings,profile:e,env:this.shellEnv,...this.onShellCommandSpawn?{onCommandSpawn:this.onShellCommandSpawn}:{}}):void 0}buildSession(e,t,o,i){const r=this.store,n=r?.getThread(t)?.derivedFrom,c=this.resolveContextWindowFor(this.resolveProviderName(),this.resolveModelName()),d=(e.skillLibrary?.list()??[]).length>0?e.skillLibrary:void 0,p=void 0===this.explicitSkillLibrary?this.agentHost?.refreshSkills?.bind(this.agentHost):void 0,u=this.resolveRuntimeShellProfile(),m=u?this.resolveShellSettings(u):void 0,v=this.fileToolsEnabled?{workdir:m?.workdir??process.cwd()}:void 0,g=u?this.resolveSessionExecSettings(u):void 0,S=u?u.supportsSafeCommandClassification&&this.settings.shell.autoApproveSafe?u:h:void 0,f=l(this.hostMode)?this.resolveAgentInstallBinding():void 0,w=this.scheduleTools,y=this.composeCapabilityContext(e.sources.length,u),C=new s({id:t,model:this.activeModel(e),onBeforeTurn:this.assertModelUpdateIdle,...void 0===this.modelRecovery?{}:{modelRecovery:this.modelRecovery},sources:e.sources,toolSchemaPolicy:this.toolSchemaPolicy,onToolExcluded:e=>this.onAgentBootstrapIssue?.({agentName:e.agentName,message:`工具 "${e.toolName}" 的参数 schema 含当前 provider "${this.resolveToolSchemaProviderName()}" 无法接受的引用(${e.issues.map(e=>e.ref).join("、")}),已从本会话工具集移除`}),capabilityContext:y,resolveDynamicCapabilityContext:async e=>{const[s,t]=await Promise.all([this.inspectVcsContext(y.cwd),this.resolveDynamicCapabilityContext?.(e)??{}]),o=t.vcs??s;return{...t.ruleIds?{ruleIds:t.ruleIds}:{},...o?{vcs:o}:{},...t.origin?{origin:t.origin}:{}}},...d?{skillLibrary:d}:{},...p?{refreshSkillLibrary:e=>p({...this.hostOperation(),signal:e})}:{},...this.workspaceInstructions?{workspaceInstructions:this.workspaceInstructions}:{},...v?{fileTools:v}:{},...m?{bash:m}:{},...S?{bashClassifier:S}:{},...g?{bashSession:g}:{},...f?{agentInstall:f}:{},...w?{schedules:{port:w,sessionCwd:y.cwd,includeCreate:a(this.hostMode)}}:{},maxSteps:this.maxSteps,compaction:this.settings.compaction,turnTimeoutMs:this.settings.turnTimeoutMs,debugEvents:this.debugEvents,...this.providerOptions?{providerOptions:this.providerOptions}:{},...this.structuredOutputProviderOptions?{structuredOutputProviderOptions:this.structuredOutputProviderOptions}:{},...this.structuredOutputReasoning?{structuredOutputReasoning:this.structuredOutputReasoning}:{},onProviderOptionsChange:e=>this.syncProviderOptions(e),...void 0!==c?{contextWindow:c.window,contextWindowSource:c.source}:{},...this.policy?{policy:this.policy}:{},initialMessages:o,...void 0!==n?{derivedFrom:n}:{},...i?{initialCheckpoint:i}:{},...r?{onAcceptInput:(e,s)=>r.acceptTurnInput(t,e,s),onRecordInputSkillCheckpoint:(e,s)=>r.recordTurnSkillCheckpoint(t,e,s),getInputSkillCheckpoint:e=>r.getTurnInputSkillCheckpoint(t,e),onPersist:(e,s)=>r.appendMessages(t,e,s),onReplace:e=>r.replaceMessages(t,e),onToolExecution:e=>r.appendToolExecution(t,e),listToolExecutions:e=>r.listToolExecutions(t,e),getToolExecution:e=>r.getToolExecution(t,e),recoverUncoveredToolExecutions:()=>this.recoverUncoveredToolExecutionContext(t),listTranscriptMessages:e=>r.listTranscriptMessages(t,e),commitCompaction:e=>r.commitCompaction(t,e),readCheckpointTranscript:e=>r.readCheckpointTranscript(t,e)}:{},onClose:()=>{this.liveSessions.get(t)===C&&this.liveSessions.delete(t)}});return this.liveSessions.set(t,C),C}recoverUncoveredToolExecutionContext(e){const s=this.store?.recoverUncoveredToolExecutions(e,p);return void 0===s?[]:[s]}assertModelUpdateIdle=()=>{if(void 0!==this.switchingProviderName)throw new Error("模型配置正在更新,请稍后再试")};syncProviderOptions(e){this.assertModelUpdateIdle(),this.switchingProviderName=this.provider;try{this.agentHost?.updateSampling(this.modelOverride??this.explicitModel,e),this.providerOptions=e}finally{this.switchingProviderName=void 0}}switchModel(e){this.assertAcceptingSessions(),this.assertModelUpdateIdle(),this.switchingProviderName=e.provider;try{const s=this.resolveContextWindowFor(e.provider,e.modelName),t={model:e.model,...void 0===e.modelRecovery?{}:{modelRecovery:e.modelRecovery},...void 0!==s?{contextWindow:s.window,contextWindowSource:s.source}:{},...e.providerOptions?{providerOptions:e.providerOptions}:{},...e.structuredOutputProviderOptions?{structuredOutputProviderOptions:e.structuredOutputProviderOptions}:{},...e.structuredOutputReasoning?{structuredOutputReasoning:e.structuredOutputReasoning}:{},toolSchemaPolicy:e.toolSchemaPolicy??m};for(const e of this.liveSessions.values())if(!e.canSwitchModel())throw new Error("存在正在生成回复的会话,稍后再切换模型");this.agentHost?.updateSampling(e.model,e.providerOptions);for(const e of this.liveSessions.values())e.switchModel(t);this.modelOverride=e.model,this.modelName=e.modelName,this.provider=e.provider,this.toolSchemaPolicy=t.toolSchemaPolicy,this.providerOptions=e.providerOptions,this.modelRecovery=e.modelRecovery,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning;for(const s of this.liveSessions.keys())this.store?.updateModel(s,e.modelName);return s}finally{this.switchingProviderName=void 0}}ensureReady(){return this.assertAcceptingSessions(),this.ready||(this.ready=this.bootstrap()),this.ready}hostOperation(){return{model:this.modelOverride??this.explicitModel,...this.providerOptions?{providerOptions:this.providerOptions}:{},signal:this.shutdownController.signal}}async bootstrap(){const e=this.agentHost?await this.agentHost.prepare(this.hostOperation()):{sources:this.explicitSources??[]};this.assertAcceptingSessions(),this.resolvedCatalog=e.catalog??[];const s=e.skillLibrary,t=null===this.explicitSkillLibrary?void 0:this.explicitSkillLibrary??s,o=this.modelOverride??this.explicitModel;return this.agentHost?.updateSampling(o,this.providerOptions),{model:o,sources:e.sources,...t?{skillLibrary:t}:{}}}async prepareAgentRefresh(e){this.assertAcceptingSessions();const s=this.refreshChain.then(()=>this.runAgentRefresh(e));return this.refreshChain=s.then(()=>{},()=>{}),s}async runAgentRefresh(e){const s=await this.ensureReady();if(this.assertAcceptingSessions(),!this.agentHost)throw new Error("Agent refresh requires an agentHost");const t=await this.agentHost.refresh(e,this.hostOperation());this.assertAcceptingSessions();const o=[...s.sources.filter(e=>e.agentName!==t.source.agentName),t.source],i=null===this.explicitSkillLibrary?void 0:this.explicitSkillLibrary??t.skillLibrary;this.agentHost.updateSampling(this.activeModel(s),this.providerOptions),this.ready=Promise.resolve({model:this.activeModel(s),sources:o,...i?{skillLibrary:i}:{}});const r=i?.list()??[],n=i&&r.length>0?i:void 0,l=this.resolveRuntimeShellProfile();return{source:t.source,...n?{skillLibrary:n}:{},capabilityContext:this.composeCapabilityContext(o.length,l)}}composeCapabilityContext(e,s){const t=this.resolveAgentOnboardingInfo();return{profile:s?.toolName??"no-shell",hostMode:this.hostMode,cwd:process.cwd(),platform:process.platform,...s?{shellHints:s.systemPromptHints()}:{},agentCount:e,...t?{agentOnboardingCatalog:t}:{}}}resolveAgentOnboardingInfo(){return this.resolvedCatalog.length>0?this.resolvedCatalog:void 0}resolveAgentInstallBinding(){if(this.agentHost?.install&&0!==this.resolvedCatalog.length)return{catalog:this.resolvedCatalog,install:(e,s)=>this.installCatalogAgent(e,s)}}installCatalogAgent(e,s){this.assertAcceptingSessions();const t=this.runAgentInstall(e,s);return this.pendingInstalls.add(t),t.then(()=>this.pendingInstalls.delete(t),()=>this.pendingInstalls.delete(t)),t}async runAgentInstall(e,s){const t=this.agentHost;if(!t?.install||!this.resolvedCatalog.some(s=>s.shortName===e))return{outcome:{ok:!1,message:`未知的官方 Agent 短名: ${e}`}};const{outcome:o}=await t.install(e,s,this.shutdownController.signal);if(!o.ok||this.closing)return{outcome:o};try{const e=await this.ensureReady();if(this.assertAcceptingSessions(),e.sources.some(e=>e.agentName===o.agentName))return s(`Agent "${o.agentName}" 本会话已接入旧版本连接,更新需重启 roll chat 生效。`),{outcome:o};const t=await this.prepareAgentRefresh(o.agentName);return{outcome:o,refresh:t}}catch(e){return s(`接入新 Agent 失败:${e instanceof Error?e.message:String(e)}`),{outcome:o}}}resolveProviderName(){return this.provider}resolveContextWindowFor(e,s){return t({provider:e,model:s,...void 0!==this.settings.contextWindow?{override:this.settings.contextWindow}:{},catalog:this.modelCatalog})}resolveModelName(){return this.modelName}resolveToolSchemaProviderName(){return this.switchingProviderName??this.resolveProviderName()}activeModel(e){return this.modelOverride??e.model}async getContextSummary(){const e=await this.ensureReady();this.assertAcceptingSessions();const s=this.workspaceInstructions?.current()?.path;return{agentCount:e.sources.length,toolCount:e.sources.reduce((e,s)=>e+s.tools.length,0),skillCount:e.skillLibrary?.list().length??0,...void 0!==s?{instructionsPath:s}:{}}}async dispose(){return void 0!==this.disposePromise||(this.closing=!0,this.disposePromise=Promise.resolve().then(async()=>{const e=[],s=await Promise.allSettled([...this.liveSessions.values()].map(e=>e.close()));for(const t of s)"rejected"===t.status&&e.push(t.reason);this.liveSessions.clear(),await Promise.allSettled([...this.ready?[this.ready]:[],this.refreshChain,...this.pendingInstalls]);try{await(this.agentHost?.dispose())}catch(s){e.push(s)}if(1===e.length)throw e[0];if(e.length>1)throw new AggregateError(e,"ConversationEngine 关闭 session 与宿主资源失败。")}),this.shutdownController.abort(v())),this.disposePromise}}
1
+ import{randomUUID as e}from"node:crypto";import{AgentSession as s}from"./agent-session.js";import{resolveModelContextWindow as t}from"./context-window.js";import{createDefaultModelCatalog as o}from"./model-catalog-default.js";import{createWorkspaceInstructionsSource as i,parseWorkspaceInstructionsSetting as r}from"./workspace-instructions.js";import{CAPABILITY_HOST_MODES as n,shouldOfferAgentInstall as l,shouldOfferScheduleCreate as a}from"./capability-manifest.js";import{}from"../tool-bridge/bash-tool.js";import{unknownCommandClassifier as h}from"../types/command-classification.js";import{resolveShellProfile as c}from"../bash/profile.js";import{inspectGitVcsContext as d}from"./vcs-context.js";import{createToolLedgerGapRecoveryMessage as p}from"./cancelled-turn-recovery.js";const u="ConversationEngine is closing",m=e=>0===e.length;export function buildSessionExecSettings(e){const s=e.settings.shell;return{workdir:process.cwd(),profile:e.profile,maxSessions:s.session.maxSessions,defaultYieldMs:s.session.defaultYieldMs,maxOutputTokens:s.session.maxOutputTokens,bufferCapacity:s.maxCaptureBytes,env:e.env,...e.onCommandSpawn?{onCommandSpawn:e.onCommandSpawn}:{}}}export function buildSessionBashSettings(e){const s=e.settings.shell;return{workdir:process.cwd(),defaultTimeoutMs:s.defaultTimeoutMs,maxTimeoutMs:s.maxTimeoutMs,turnTimeoutMs:e.settings.turnTimeoutMs,maxCaptureBytes:s.maxCaptureBytes,maxModelOutputChars:s.maxModelOutputChars,profile:e.profile,env:e.env,...e.onCommandSpawn?{onCommandSpawn:e.onCommandSpawn}:{}}}function v(){return new Error(u)}function g(e){if(null===e.workspaceInstructions)return;if(void 0!==e.workspaceInstructions)return e.workspaceInstructions;const s=process.cwd();return i({cwd:s,setting:r(e.settings.instructions,s),...e.onWorkspaceInstructionsIssue?{onIssue:e.onWorkspaceInstructionsIssue}:{}})}export class ConversationEngine{settings;agentHost;store;policy;fileToolsEnabled;maxSteps;providerOptions;modelRecovery;resolveReasoningPresentation;modelOverride;modelName;provider;toolSchemaPolicy;switchingProviderName;modelCatalog;structuredOutputProviderOptions;structuredOutputReasoning;debugEvents;explicitModel;explicitSources;explicitSkillLibrary;workspaceInstructions;onAgentBootstrapIssue;hostMode;scheduleTools;resolveDynamicCapabilityContext;sessionExecEnabled;explicitShellProfile;resolveShellProfileFn;inspectVcsContext;shellEnv;onShellCommandSpawn;ready;refreshChain=Promise.resolve();resolvedCatalog=[];pendingInstalls=new Set;shellProfileResolution;shellUnsupportedWarned=!1;liveSessions=new Map;shutdownController=new AbortController;disposePromise;closing=!1;constructor(e){if(!e.model)throw new Error("ConversationEngine requires a model supplied by its host");if(void 0!==e.agentHost&&void 0!==e.sources)throw new Error("ConversationEngine accepts either sources or agentHost, not both");this.settings=e.settings,this.agentHost=e.agentHost,this.provider=e.provider,this.modelName=e.modelName,this.toolSchemaPolicy=e.toolSchemaPolicy??m,this.store=e.store,this.modelCatalog=e.modelCatalog??o(),this.policy=e.policy,this.fileToolsEnabled=e.fileToolsEnabled??!0,this.maxSteps=e.maxSteps??e.settings.maxSteps,this.providerOptions=e.providerOptions,this.modelRecovery=e.modelRecovery,this.resolveReasoningPresentation=e.resolveReasoningPresentation,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.debugEvents=e.debugEvents??!1,this.hostMode=e.hostMode??n.embedded,this.scheduleTools=e.scheduleTools??void 0,this.resolveDynamicCapabilityContext=e.resolveDynamicCapabilityContext,this.sessionExecEnabled=e.sessionExecEnabled??!0,this.explicitShellProfile=e.shellProfile,this.resolveShellProfileFn=e.resolveShellProfileFn??c,this.explicitModel=e.model,this.explicitSources=e.sources,this.explicitSkillLibrary=e.skillLibrary,this.workspaceInstructions=g(e),this.onAgentBootstrapIssue=e.onAgentBootstrapIssue,this.inspectVcsContext=e.inspectVcsContext??d,this.shellEnv={...e.shellEnv??process.env},this.onShellCommandSpawn=e.onShellCommandSpawn}async createSession(s={}){this.assertAcceptingSessions();const t=await this.ensureReady();this.assertAcceptingSessions();const o=this.store?this.store.createThread({...void 0===s.id?{}:{id:s.id},...void 0===s.origin?{}:{origin:s.origin},...s.title?{title:s.title}:{},model:this.resolveModelName()}):s.id??e();return this.buildSession(t,o,[])}async resumeSession(e){if(this.assertAcceptingSessions(),!this.store)throw new Error("resumeSession requires a ThreadStore");if("scheduled"===this.store.getThread(e)?.origin.kind)throw new Error("定时执行会话是只读记录;请基于该次运行创建新对话");const s=this.liveSessions.get(e);if(void 0!==s)return s;if(!this.store.hasThread(e))throw new Error(`Thread "${e}" 不存在`);const t=await this.ensureReady();this.assertAcceptingSessions();const o=this.liveSessions.get(e);if(void 0!==o)return o;this.recoverUncoveredToolExecutionContext(e);const i=this.store.loadSessionState(e);return this.buildSession(t,e,i.messages,i.checkpoint)}async forkSession(e,s={}){if(this.assertAcceptingSessions(),!this.store)throw new Error("forkSession requires a ThreadStore");const t=await this.ensureReady();this.assertAcceptingSessions();const o=this.store.forkSnapshot(e,{...s,model:this.resolveModelName()});try{this.recoverUncoveredToolExecutionContext(o);const e=this.store.loadSessionState(o);return this.buildSession(t,o,e.messages,e.checkpoint)}catch(e){throw this.store.deleteThread(o),e}}assertAcceptingSessions(){if(this.closing)throw v()}resolveRuntimeShellProfile(){if(!this.settings.shell.enabled)return;if(void 0!==this.explicitShellProfile)return this.explicitShellProfile??void 0;void 0===this.shellProfileResolution&&(this.shellProfileResolution=this.resolveShellProfileFn({platform:process.platform,env:this.shellEnv}));const e=this.shellProfileResolution;if(e.supported)return e.profile;if(!this.shellUnsupportedWarned){this.shellUnsupportedWarned=!0;const s="pwsh-version-unsupported"===e.reason?"检测到的 pwsh 版本低于 7":"未检测到 PowerShell 7 (pwsh)";process.stderr.write(`roll chat: ${s},Windows 原生 shell 工具已跳过注册;可运行 winget install Microsoft.PowerShell\n`)}}resolveShellSettings(e){return buildSessionBashSettings({settings:this.settings,profile:e,env:this.shellEnv,...this.onShellCommandSpawn?{onCommandSpawn:this.onShellCommandSpawn}:{}})}resolveSessionExecSettings(e){if(!this.sessionExecEnabled)return;const s=this.settings.shell;return s.enabled&&s.session.enabled&&e.supportsSessionExec?buildSessionExecSettings({settings:this.settings,profile:e,env:this.shellEnv,...this.onShellCommandSpawn?{onCommandSpawn:this.onShellCommandSpawn}:{}}):void 0}buildSession(e,t,o,i){const r=this.store,n=r?.getThread(t)?.derivedFrom,c=this.resolveContextWindowFor(this.resolveProviderName(),this.resolveModelName()),d=(e.skillLibrary?.list()??[]).length>0?e.skillLibrary:void 0,p=void 0===this.explicitSkillLibrary?this.agentHost?.refreshSkills?.bind(this.agentHost):void 0,u=this.resolveRuntimeShellProfile(),m=u?this.resolveShellSettings(u):void 0,v=this.fileToolsEnabled?{workdir:m?.workdir??process.cwd()}:void 0,g=u?this.resolveSessionExecSettings(u):void 0,S=u?u.supportsSafeCommandClassification&&this.settings.shell.autoApproveSafe?u:h:void 0,f=l(this.hostMode)?this.resolveAgentInstallBinding():void 0,w=this.scheduleTools,y=this.composeCapabilityContext(e.sources.length,u),C=new s({id:t,model:this.activeModel(e),...this.resolveReasoningPresentation?{resolveReasoningPresentation:this.resolveReasoningPresentation}:{},onBeforeTurn:this.assertModelUpdateIdle,...void 0===this.modelRecovery?{}:{modelRecovery:this.modelRecovery},sources:e.sources,toolSchemaPolicy:this.toolSchemaPolicy,onToolExcluded:e=>this.onAgentBootstrapIssue?.({agentName:e.agentName,message:`工具 "${e.toolName}" 的参数 schema 含当前 provider "${this.resolveToolSchemaProviderName()}" 无法接受的引用(${e.issues.map(e=>e.ref).join("、")}),已从本会话工具集移除`}),capabilityContext:y,resolveDynamicCapabilityContext:async e=>{const[s,t]=await Promise.all([this.inspectVcsContext(y.cwd),this.resolveDynamicCapabilityContext?.(e)??{}]),o=t.vcs??s;return{...t.ruleIds?{ruleIds:t.ruleIds}:{},...o?{vcs:o}:{},...t.origin?{origin:t.origin}:{}}},...d?{skillLibrary:d}:{},...p?{refreshSkillLibrary:e=>p({...this.hostOperation(),signal:e})}:{},...this.workspaceInstructions?{workspaceInstructions:this.workspaceInstructions}:{},...v?{fileTools:v}:{},...m?{bash:m}:{},...S?{bashClassifier:S}:{},...g?{bashSession:g}:{},...f?{agentInstall:f}:{},...w?{schedules:{port:w,sessionCwd:y.cwd,includeCreate:a(this.hostMode)}}:{},maxSteps:this.maxSteps,compaction:this.settings.compaction,turnTimeoutMs:this.settings.turnTimeoutMs,debugEvents:this.debugEvents,...this.providerOptions?{providerOptions:this.providerOptions}:{},...this.structuredOutputProviderOptions?{structuredOutputProviderOptions:this.structuredOutputProviderOptions}:{},...this.structuredOutputReasoning?{structuredOutputReasoning:this.structuredOutputReasoning}:{},onProviderOptionsChange:e=>this.syncProviderOptions(e),...void 0!==c?{contextWindow:c.window,contextWindowSource:c.source}:{},...this.policy?{policy:this.policy}:{},initialMessages:o,...void 0!==n?{derivedFrom:n}:{},...i?{initialCheckpoint:i}:{},...r?{onAcceptInput:(e,s)=>r.acceptTurnInput(t,e,s),onRecordInputSkillCheckpoint:(e,s)=>r.recordTurnSkillCheckpoint(t,e,s),getInputSkillCheckpoint:e=>r.getTurnInputSkillCheckpoint(t,e),onPersist:(e,s)=>r.appendMessages(t,e,s),onReplace:e=>r.replaceMessages(t,e),onToolExecution:e=>r.appendToolExecution(t,e),listToolExecutions:e=>r.listToolExecutions(t,e),getToolExecution:e=>r.getToolExecution(t,e),recoverUncoveredToolExecutions:()=>this.recoverUncoveredToolExecutionContext(t),listTranscriptMessages:e=>r.listTranscriptMessages(t,e),commitCompaction:e=>r.commitCompaction(t,e),readCheckpointTranscript:e=>r.readCheckpointTranscript(t,e)}:{},onClose:()=>{this.liveSessions.get(t)===C&&this.liveSessions.delete(t)}});return this.liveSessions.set(t,C),C}recoverUncoveredToolExecutionContext(e){const s=this.store?.recoverUncoveredToolExecutions(e,p);return void 0===s?[]:[s]}assertModelUpdateIdle=()=>{if(void 0!==this.switchingProviderName)throw new Error("模型配置正在更新,请稍后再试")};syncProviderOptions(e){this.assertModelUpdateIdle(),this.switchingProviderName=this.provider;try{this.agentHost?.updateSampling(this.modelOverride??this.explicitModel,e),this.providerOptions=e}finally{this.switchingProviderName=void 0}}switchModel(e){this.assertAcceptingSessions(),this.assertModelUpdateIdle(),this.switchingProviderName=e.provider;try{const s=this.resolveContextWindowFor(e.provider,e.modelName),t={model:e.model,...void 0===e.modelRecovery?{}:{modelRecovery:e.modelRecovery},...void 0!==s?{contextWindow:s.window,contextWindowSource:s.source}:{},...e.providerOptions?{providerOptions:e.providerOptions}:{},...e.structuredOutputProviderOptions?{structuredOutputProviderOptions:e.structuredOutputProviderOptions}:{},...e.structuredOutputReasoning?{structuredOutputReasoning:e.structuredOutputReasoning}:{},toolSchemaPolicy:e.toolSchemaPolicy??m};for(const e of this.liveSessions.values())if(!e.canSwitchModel())throw new Error("存在正在生成回复的会话,稍后再切换模型");this.agentHost?.updateSampling(e.model,e.providerOptions);for(const e of this.liveSessions.values())e.switchModel(t);this.modelOverride=e.model,this.modelName=e.modelName,this.provider=e.provider,this.toolSchemaPolicy=t.toolSchemaPolicy,this.providerOptions=e.providerOptions,this.modelRecovery=e.modelRecovery,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning;for(const s of this.liveSessions.keys())this.store?.updateModel(s,e.modelName);return s}finally{this.switchingProviderName=void 0}}ensureReady(){return this.assertAcceptingSessions(),this.ready||(this.ready=this.bootstrap()),this.ready}hostOperation(){return{model:this.modelOverride??this.explicitModel,...this.providerOptions?{providerOptions:this.providerOptions}:{},signal:this.shutdownController.signal}}async bootstrap(){const e=this.agentHost?await this.agentHost.prepare(this.hostOperation()):{sources:this.explicitSources??[]};this.assertAcceptingSessions(),this.resolvedCatalog=e.catalog??[];const s=e.skillLibrary,t=null===this.explicitSkillLibrary?void 0:this.explicitSkillLibrary??s,o=this.modelOverride??this.explicitModel;return this.agentHost?.updateSampling(o,this.providerOptions),{model:o,sources:e.sources,...t?{skillLibrary:t}:{}}}async prepareAgentRefresh(e){this.assertAcceptingSessions();const s=this.refreshChain.then(()=>this.runAgentRefresh(e));return this.refreshChain=s.then(()=>{},()=>{}),s}async runAgentRefresh(e){const s=await this.ensureReady();if(this.assertAcceptingSessions(),!this.agentHost)throw new Error("Agent refresh requires an agentHost");const t=await this.agentHost.refresh(e,this.hostOperation());this.assertAcceptingSessions();const o=[...s.sources.filter(e=>e.agentName!==t.source.agentName),t.source],i=null===this.explicitSkillLibrary?void 0:this.explicitSkillLibrary??t.skillLibrary;this.agentHost.updateSampling(this.activeModel(s),this.providerOptions),this.ready=Promise.resolve({model:this.activeModel(s),sources:o,...i?{skillLibrary:i}:{}});const r=i?.list()??[],n=i&&r.length>0?i:void 0,l=this.resolveRuntimeShellProfile();return{source:t.source,...n?{skillLibrary:n}:{},capabilityContext:this.composeCapabilityContext(o.length,l)}}composeCapabilityContext(e,s){const t=this.resolveAgentOnboardingInfo();return{profile:s?.toolName??"no-shell",hostMode:this.hostMode,cwd:process.cwd(),platform:process.platform,...s?{shellHints:s.systemPromptHints()}:{},agentCount:e,...t?{agentOnboardingCatalog:t}:{}}}resolveAgentOnboardingInfo(){return this.resolvedCatalog.length>0?this.resolvedCatalog:void 0}resolveAgentInstallBinding(){if(this.agentHost?.install&&0!==this.resolvedCatalog.length)return{catalog:this.resolvedCatalog,install:(e,s)=>this.installCatalogAgent(e,s)}}installCatalogAgent(e,s){this.assertAcceptingSessions();const t=this.runAgentInstall(e,s);return this.pendingInstalls.add(t),t.then(()=>this.pendingInstalls.delete(t),()=>this.pendingInstalls.delete(t)),t}async runAgentInstall(e,s){const t=this.agentHost;if(!t?.install||!this.resolvedCatalog.some(s=>s.shortName===e))return{outcome:{ok:!1,message:`未知的官方 Agent 短名: ${e}`}};const{outcome:o}=await t.install(e,s,this.shutdownController.signal);if(!o.ok||this.closing)return{outcome:o};try{const e=await this.ensureReady();if(this.assertAcceptingSessions(),e.sources.some(e=>e.agentName===o.agentName))return s(`Agent "${o.agentName}" 本会话已接入旧版本连接,更新需重启 roll chat 生效。`),{outcome:o};const t=await this.prepareAgentRefresh(o.agentName);return{outcome:o,refresh:t}}catch(e){return s(`接入新 Agent 失败:${e instanceof Error?e.message:String(e)}`),{outcome:o}}}resolveProviderName(){return this.provider}resolveContextWindowFor(e,s){return t({provider:e,model:s,...void 0!==this.settings.contextWindow?{override:this.settings.contextWindow}:{},catalog:this.modelCatalog})}resolveModelName(){return this.modelName}resolveToolSchemaProviderName(){return this.switchingProviderName??this.resolveProviderName()}activeModel(e){return this.modelOverride??e.model}async getContextSummary(){const e=await this.ensureReady();this.assertAcceptingSessions();const s=this.workspaceInstructions?.current()?.path;return{agentCount:e.sources.length,toolCount:e.sources.reduce((e,s)=>e+s.tools.length,0),skillCount:e.skillLibrary?.list().length??0,...void 0!==s?{instructionsPath:s}:{}}}async dispose(){return void 0!==this.disposePromise||(this.closing=!0,this.disposePromise=Promise.resolve().then(async()=>{const e=[],s=await Promise.allSettled([...this.liveSessions.values()].map(e=>e.close()));for(const t of s)"rejected"===t.status&&e.push(t.reason);this.liveSessions.clear(),await Promise.allSettled([...this.ready?[this.ready]:[],this.refreshChain,...this.pendingInstalls]);try{await(this.agentHost?.dispose())}catch(s){e.push(s)}if(1===e.length)throw e[0];if(e.length>1)throw new AggregateError(e,"ConversationEngine 关闭 session 与宿主资源失败。")}),this.shutdownController.abort(v())),this.disposePromise}}
@@ -21,6 +21,7 @@ export declare class RuntimeProtocolAdapter {
21
21
  private transportFailed;
22
22
  private controlsService;
23
23
  private protocolVersion;
24
+ private unsubscribeReasoningText;
24
25
  private capabilityRevision;
25
26
  private capabilityMethods;
26
27
  private capabilityResult;
@@ -1 +1 @@
1
- import{randomUUID as e}from"node:crypto";import{RUNTIME_ERROR_CODES as t,RUNTIME_EVENT_NOTIFICATION as i,RUNTIME_METHODS as s,RUNTIME_PROTOCOL_VERSION as r,RUNTIME_SERVER_REQUEST_METHODS as a,RUNTIME_V13_DEFAULT_REPLAY_BUFFER_BYTES as n,RUNTIME_V13_MAX_DURABLE_EVENT_RECORDS as o,RUNTIME_V13_RECOVERY_SNAPSHOT_METADATA_MAX_CHARS as c,clientCapabilitiesSetParamsSchema as h,getRuntimeProtocolCapabilities as l,getRuntimeProtocolRegistry as p,interactionIdSchema as d,isRuntimeMethodAvailable as u,normalizeUserInputResult as v,parseRuntimeMethodParamsForVersion as m,projectClientCapabilitiesSetResult as b,projectRuntimeEventEnvelopeForVersion as R,projectThreadSnapshotForVersion as f,projectOperationViewForVersion as y,runtimeMethodSchemas as I,runtimeDurableEventV16Schema as q,turnIdSchema as g}from"@roll-agent/protocol";import{RuntimeService as w,RuntimeServiceError as S}from"../service/runtime-service.js";import{RuntimeClientRequestCancelledError as V,RuntimeClientRequestCoordinator as C,RuntimeClientRequestExpiredError as P,createRuntimeClientResponderId as A,getRuntimeClientRequestCoordinatorInternal as U}from"./runtime-client-request-coordinator.js";const E="客户端未完成审批请求,Runtime 已终止当前 Turn",T="客户端未完成用户输入请求",z=new WeakSet,G=o,k=n;function B(e){return`user-input:${e}`}function F(e){switch(e.status){case"resolved":return"approve"===e.decision?"审批已批准":"审批已拒绝";case"cancelled":return e.reason;case"expired":return e.reason??"审批已到期"}}export class RuntimeProtocolAdapter{service;connection;clientRequests;responderId;unsubscribe;unsubscribeFatalError;unsubscribeUserInput;settlementTasks=new Set;detachResponder;initialized=!1;closing=!1;transportFailed=!1;controlsService=!1;protocolVersion;capabilityRevision;capabilityMethods;capabilityResult;replayGates=new Map;eventSequence=0;closePromise;constructor(e,i,s){if(z.has(e))throw new S(t.capabilityUnavailable,"当前 RuntimeService 已绑定 Runtime Protocol Adapter");z.add(e),this.controlsService=!0,this.service=e,this.connection=i,this.clientRequests=s,this.responderId=A();try{this.unsubscribe=e.onEvent(e=>this.handleServiceEvent(e))}catch(e){throw this.releaseServiceControl(),e}try{this.unsubscribeUserInput=e.onUserInputInteraction(e=>this.handleUserInputInteraction(e))}catch(e){throw this.unsubscribe(),this.releaseServiceControl(),e}try{this.unsubscribeFatalError=e.onFatalError(()=>this.closeBrokenTransport())}catch(e){throw this.unsubscribeUserInput(),this.unsubscribe(),this.releaseServiceControl(),e}}dispatchEventResume(e){if(!this.initialized)throw new S(t.initializeRequired,"调用 Runtime Protocol 方法前必须先完成 initialize");if("1.3"!==this.protocolVersion&&"1.4"!==this.protocolVersion&&"1.5"!==this.protocolVersion&&"1.6"!==this.protocolVersion)throw new S(t.capabilityUnavailable,`Runtime Protocol ${String(this.protocolVersion)} 不支持方法:${e.method}`);const i=I[s.runtimeEventsResume].params.parse(e.params);if(this.replayGates.has(i.threadId))throw new S(t.threadBusy,`Thread "${i.threadId}" 已有进行中的 Runtime Event replay`,{retryable:!0});const r={threadId:i.threadId,buffered:[],bufferedBytes:0};this.replayGates.set(i.threadId,r);try{const e=this.service.resumeEvents(i);for(const t of e.events){const e={protocolVersion:"1.6",runtimeInstanceId:this.service.runtimeInstanceId,sequence:this.eventSequence,timestamp:t.timestamp,threadId:i.threadId,...void 0===t.turnId?{}:{turnId:g.parse(t.turnId)},durability:"durable",eventId:t.eventId,cursor:t.cursor,event:q.parse(t.event)};if(!this.sendEvent(e))throw new Error("Runtime Event replay transport write failed")}return{result:{throughCursor:e.throughCursor,replayedCount:e.replayedCount},afterResponse:e=>{e?this.flushReplayGate(r):this.releaseReplayGate(r)}}}catch(e){throw this.releaseReplayGate(r),e}}handles(e){return u(r,e)}handleResponse(e){if(void 0===this.protocolVersion||!l(this.protocolVersion).serverRequests||void 0===this.detachResponder)return!1;return U(this.clientRequests).handleResponseForAttachment(this.detachResponder,e)??this.clientRequests.handleResponse(this.responderId,e)}async dispatch(e){return e.method===s.runtimeEventsResume?this.dispatchEventResume(e):e.method===s.clientCapabilitiesSet?this.dispatchClientCapabilitiesSet(e):{result:await this.dispatchValue(e)}}dispatchClientCapabilitiesSet(e){if(!this.initialized)throw new S(t.initializeRequired,"调用 Runtime Protocol 方法前必须先完成 initialize");if(void 0===this.protocolVersion||!l(this.protocolVersion).serverRequestCapabilityNegotiation)throw new S(t.capabilityUnavailable,`Runtime Protocol ${String(this.protocolVersion)} 不支持 capability negotiation:${e.method}`);return this.setClientCapabilities(h.parse(e.params))}async dispatchValue(e){if(!this.handles(e.method))throw new S(t.capabilityUnavailable,`未知 Runtime Protocol 方法:${e.method}`);if(e.method===s.initialize){if(this.initialized)throw new S(t.capabilityUnavailable,"当前连接已完成 initialize,不能重新协商 Runtime Protocol");const i=I[s.initialize].params.parse(e.params),r=this.service.initialize(i);if(this.protocolVersion=r.protocolVersion,l(r.protocolVersion).serverRequests){const e=l(r.protocolVersion).serverRequestCapabilityNegotiation;if(this.detachResponder=this.clientRequests.attachResponder({id:this.responderId,scopeId:r.runtimeInstanceId,send:e=>this.connection.send(e),close:()=>this.connection.close()},{acceptedServerRequestMethods:e?[]:p(r.protocolVersion).serverRequestMethods,capabilitiesAcknowledged:!e}),e){if(!(U(this.clientRequests).beginCapabilityNegotiationForAttachment(this.detachResponder)??this.clientRequests.beginResponderCapabilityNegotiation(this.responderId)))throw new S(t.capabilityUnavailable,"Runtime 客户端 responder 无法进入 capability negotiation")}}return this.initialized=!0,r}if(!this.initialized)throw new S(t.initializeRequired,"调用 Runtime Protocol 方法前必须先完成 initialize");if(void 0===this.protocolVersion||!u(this.protocolVersion,e.method))throw new S(t.capabilityUnavailable,`Runtime Protocol ${String(this.protocolVersion)} 不支持方法:${e.method}`);if(e.method===s.approvalRespond&&void 0!==this.protocolVersion&&!l(this.protocolVersion).clientApprovalResponses)throw new S(t.capabilityUnavailable,"当前协商协议的审批只能通过 approval.request 响应完成");switch(e.method){case s.threadList:return this.service.listThreads(I[s.threadList].params.parse(e.params));case s.threadCreate:return this.service.createThread(I[s.threadCreate].params.parse(e.params));case s.threadOpen:return this.projectThreadSnapshot(await this.service.openThread(I[s.threadOpen].params.parse(e.params)));case s.threadSnapshot:{const t=m(this.protocolVersion,s.threadSnapshot,e.params),i=("1.3"===this.protocolVersion||"1.4"===this.protocolVersion||"1.5"===this.protocolVersion||"1.6"===this.protocolVersion)&&"recovery"in t&&!0===t.recovery;return this.projectThreadSnapshot(this.service.snapshotThread({threadId:t.threadId,...void 0===t.messageBeforeSequence?{}:{messageBeforeSequence:t.messageBeforeSequence},...void 0===t.operationBeforeSequence?{}:{operationBeforeSequence:t.operationBeforeSequence},limit:t.limit}),i)}case s.threadRename:return this.service.renameThread(I[s.threadRename].params.parse(e.params));case s.threadDelete:return this.service.deleteThread(I[s.threadDelete].params.parse(e.params));case s.threadDetach:return this.service.detachThread(I[s.threadDetach].params.parse(e.params));case s.threadCapabilities:return this.service.threadCapabilities(I[s.threadCapabilities].params.parse(e.params));case s.turnStart:return this.service.startTurn(m(this.protocolVersion,s.turnStart,e.params));case s.turnCancel:return this.service.cancelTurn(I[s.turnCancel].params.parse(e.params));case s.approvalRespond:return this.service.respondApproval(m(this.protocolVersion,s.approvalRespond,e.params));case s.approvalPreview:return this.service.getApprovalPreview(I[s.approvalPreview].params.parse(e.params));case s.operationGet:{const t=this.service.getOperation(I[s.operationGet].params.parse(e.params));return{operation:null===t.operation?null:y(this.protocolVersion,t.operation)}}case s.operationResultGet:return this.service.getOperationResult(I[s.operationResultGet].params.parse(e.params));case s.attachmentStage:return this.service.stageAttachment(I[s.attachmentStage].params.parse(e.params));case s.attachmentChunk:return this.service.appendAttachmentChunk(I[s.attachmentChunk].params.parse(e.params));case s.attachmentCommit:return this.service.commitAttachment(I[s.attachmentCommit].params.parse(e.params));case s.attachmentRelease:return this.service.releaseAttachment(I[s.attachmentRelease].params.parse(e.params));case s.runtimeEventsResume:throw new Error("runtime.events.resume requires the response-barrier dispatch path");case s.clientCapabilitiesSet:throw new Error("client.capabilities.set requires the response-barrier dispatch path")}}async close(){this.closePromise??=this.performClose(),await this.closePromise}disposeConstructionFailure(){this.closing=!0,this.unsubscribeFatalError(),this.unsubscribe(),this.unsubscribeUserInput(),this.releaseServiceControl()}releaseServiceControl(){this.controlsService&&(z.delete(this.service),this.controlsService=!1)}async performClose(){for(this.closing=!0,this.replayGates.clear(),this.service.setUserInputAvailable(!1),this.detachResponder?.(),this.detachResponder=void 0;this.settlementTasks.size>0;)await Promise.allSettled([...this.settlementTasks]);this.unsubscribeFatalError(),this.unsubscribe(),this.unsubscribeUserInput()}handleServiceEvent(e){if(!this.initialized||this.closing||void 0===this.protocolVersion)return;const t=this.replayGates.get(e.threadId);void 0===t?this.deliverLiveEvent(e):this.bufferReplayLiveEvent(t,e)||this.closeBrokenTransport()}deliverLiveEvent(e){if(!this.initialized||this.closing||void 0===this.protocolVersion)return!1;const t=l(this.protocolVersion);return t.serverRequests&&"approval.resolved"===e.event.type&&this.clientRequests.cancel(e.event.approvalId,F(e.event.resolution)),t.serverRequests&&"approval.required"===e.event.type&&this.requestApproval(e.threadId,e.event.approval),this.sendEvent(e)}sendEvent(e){if(void 0===this.protocolVersion)return!1;if(!l(this.protocolVersion).approvalResolvedEvents&&"approval.resolved"===e.event.type)return!0;const t={...e,sequence:Math.max(this.eventSequence,e.sequence)};this.eventSequence=t.sequence+1;const s=R(this.protocolVersion,t);try{return this.connection.send({jsonrpc:"2.0",method:i,params:s}),!0}catch{return this.closeBrokenTransport(),!1}}bufferReplayLiveEvent(e,t){const i=Buffer.byteLength(JSON.stringify(t),"utf8");return e.buffered.length>=G||e.bufferedBytes+i>k?(this.releaseReplayGate(e),!1):(e.buffered.push(t),e.bufferedBytes+=i,!0)}flushReplayGate(e){if(this.replayGates.get(e.threadId)!==e)return;let t=0;for(;t<e.buffered.length;){const i=e.buffered[t];if(t+=1,void 0!==i&&!this.deliverLiveEvent(i))return void this.releaseReplayGate(e)}this.releaseReplayGate(e)}releaseReplayGate(e){this.replayGates.get(e.threadId)===e&&this.replayGates.delete(e.threadId),e.buffered.length=0,e.bufferedBytes=0}closeBrokenTransport(){if(!this.closing){this.transportFailed=!0,this.closing=!0,this.replayGates.clear(),this.service.setUserInputAvailable(!1),this.detachResponder?.(),this.detachResponder=void 0,this.unsubscribeFatalError(),this.unsubscribe(),this.unsubscribeUserInput();try{this.connection.close()}catch{}}}projectThreadSnapshot(e,i=!1){const s=this.protocolVersion;if(void 0===s)throw new S(t.initializeRequired,"投影 Thread Snapshot 前必须先完成 initialize");let r=[];if(!i&&l(s).serverRequestCapabilityNegotiation){if(void 0===this.detachResponder)throw new S(t.capabilityUnavailable,"Runtime Protocol 1.2 responder 已失效");const i=U(this.clientRequests).getPendingInteractionProjectionsForAttachment(this.detachResponder,e.thread.id)??this.clientRequests.getPendingInteractionProjections(this.responderId,e.thread.id);if(void 0===i)throw new S(t.capabilityUnavailable,"Runtime Protocol 1.2 responder attachment 已失效");r=i}if(i){const t=e=>e?.slice(0,c),i=t(e.thread.title),r=t(e.thread.model);return f(s,{...e,thread:{...e.thread,...void 0===i?{}:{title:i},...void 0===r?{}:{model:r}},messages:{items:[],nextBeforeSequence:null},operations:{items:[],nextBeforeSequence:null},pendingApprovals:[],pendingInteractions:[],recoveryProjection:!0})}return f(s,{...e,pendingInteractions:r})}handleUserInputInteraction(e){"settled"!==e.type?!this.closing&&this.initialized&&void 0!==this.protocolVersion&&l(this.protocolVersion).serverRequestCapabilityNegotiation?this.requestUserInput(e):this.service.cancelPendingUserInput(e.requestId,T):this.clientRequests.cancel(B(e.requestId),e.reason)}requestUserInput(t){const i=this.protocolVersion;if(void 0===i||!l(i).serverRequestCapabilityNegotiation)return void this.service.cancelPendingUserInput(t.requestId,T);const s={interactionId:d.parse(e()),threadId:t.threadId,turnId:t.turnId,expiresAt:t.expiresAt,sensitivity:"normal",...t.form};let r;try{r=this.clientRequests.request(a.userInputRequest,s,{key:B(t.requestId),scopeId:this.service.runtimeInstanceId,eligibleResponderId:this.responderId,protocolVersion:i,expiresAt:t.expiresAt})}catch{return void this.service.cancelPendingUserInput(t.requestId,T)}const n=r.result.then(e=>{try{const i=v(s,e);this.service.resolvePendingUserInput(t.requestId,i)}catch{this.service.cancelPendingUserInput(t.requestId,"客户端返回的用户输入不符合原始表单约束")}},e=>{const i=e instanceof P?"用户输入请求已超时":e instanceof V?e.reason:T;this.service.cancelPendingUserInput(t.requestId,i)});this.trackSettlement(n)}requestApproval(i,s){const r={threadId:i,turnId:s.turnId,approvalId:s.id};let n;try{const t=this.protocolVersion;if(void 0===t||"1.0"===t)throw new V("当前协议不支持 Server Request");const o=this.service.getPendingApprovalExpiresAt(r),c=l(t).serverRequestCapabilityNegotiation,h=c?(()=>{if(void 0===o)throw new V("Runtime Protocol 1.2 审批请求缺少绝对 expiresAt deadline");return o})():void 0,p=c?{interactionId:d.parse(e()),threadId:i,turnId:s.turnId,expiresAt:h,sensitivity:"normal",approval:s}:{threadId:i,approval:s};n=this.clientRequests.request(a.approvalRequest,p,{key:s.id,scopeId:this.service.runtimeInstanceId,eligibleResponderId:this.responderId,approvalId:s.id,protocolVersion:t,...void 0===h?{}:{expiresAt:h}})}catch{const e=Promise.resolve().then(()=>this.service.failPendingApprovalInteraction(r,E)).then(()=>{});return void this.trackSettlement(e)}const o=n.result.then(async e=>{const i="approve"===e.decision?{decision:"approve"}:{decision:"reject",...void 0!==e.reason?{reason:e.reason}:{}};try{this.service.resolvePendingApproval(r,i)}catch(e){e instanceof S&&e.rollCode===t.approvalNotFound||await this.service.failPendingApprovalInteraction(r,E)}},async e=>{if(this.closing&&!this.transportFailed)return;if(e instanceof P)return void await this.service.failPendingApprovalInteraction(r,"审批请求已到期",{status:"expired",reason:"审批请求已到期"});const t=e instanceof V?e.reason:E;await this.service.failPendingApprovalInteraction(r,t)});this.trackSettlement(o)}setClientCapabilities(e){if(void 0===this.protocolVersion||!l(this.protocolVersion).serverRequestCapabilityNegotiation||void 0===this.detachResponder)throw new S(t.capabilityUnavailable,"client.capabilities.set 仅可用于支持 capability negotiation 的 Runtime Protocol");const i=[...e.serverRequestMethods].sort();if(void 0!==this.capabilityRevision){const s=e.revision===this.capabilityRevision,r=i.length===this.capabilityMethods?.length&&i.every((e,t)=>e===this.capabilityMethods?.[t]);if(s&&r&&void 0!==this.capabilityResult)return{result:this.capabilityResult};if(e.revision<=this.capabilityRevision)throw new S(t.capabilityRevisionConflict,`Capability revision ${String(e.revision)} 与当前 revision ${String(this.capabilityRevision)} 冲突`)}const s=b(e),r=`Runtime 客户端已在 capability revision ${String(e.revision)} 撤销处理能力`,n=U(this.clientRequests),o=n.setServerRequestMethodsForAttachment(this.detachResponder,s.acceptedServerRequestMethods,r)??n.setServerRequestMethodsForResponder(this.responderId,s.acceptedServerRequestMethods,r);if(!1===o)throw new S(t.capabilityUnavailable,"Runtime 客户端 responder 已失效");return this.service.setUserInputAvailable(s.acceptedServerRequestMethods.includes(a.userInputRequest)),this.capabilityRevision=e.revision,this.capabilityMethods=i,this.capabilityResult=s,{result:s,afterResponse:e=>{e&&o()}}}trackSettlement(e){this.settlementTasks.add(e),e.finally(()=>this.settlementTasks.delete(e)).catch(()=>{})}}
1
+ import{randomUUID as e}from"node:crypto";import{RUNTIME_ERROR_CODES as t,RUNTIME_EVENT_NOTIFICATION as i,RUNTIME_METHODS as s,RUNTIME_PROTOCOL_VERSION as r,RUNTIME_SERVER_REQUEST_METHODS as n,RUNTIME_V13_DEFAULT_REPLAY_BUFFER_BYTES as a,RUNTIME_V13_MAX_DURABLE_EVENT_RECORDS as o,RUNTIME_V13_RECOVERY_SNAPSHOT_METADATA_MAX_CHARS as c,clientCapabilitiesSetParamsSchema as h,getRuntimeProtocolCapabilities as l,getRuntimeProtocolRegistry as p,interactionIdSchema as d,isRuntimeMethodAvailable as u,normalizeUserInputResult as v,parseRuntimeMethodParamsForVersion as m,projectClientCapabilitiesSetResult as b,projectRuntimeEventEnvelopeForVersion as R,projectThreadSnapshotForVersion as f,projectOperationViewForVersion as y,runtimeMethodSchemas as I,runtimeDurableEventV16Schema as g,turnIdSchema as q}from"@roll-agent/protocol";import{RuntimeService as w,RuntimeServiceError as S}from"../service/runtime-service.js";import{RuntimeClientRequestCancelledError as V,RuntimeClientRequestCoordinator as C,RuntimeClientRequestExpiredError as P,createRuntimeClientResponderId as A,getRuntimeClientRequestCoordinatorInternal as T}from"./runtime-client-request-coordinator.js";const U="客户端未完成审批请求,Runtime 已终止当前 Turn",E="客户端未完成用户输入请求",x=new WeakSet,z=o,G=a;function k(e){return`user-input:${e}`}function B(e){switch(e.status){case"resolved":return"approve"===e.decision?"审批已批准":"审批已拒绝";case"cancelled":return e.reason;case"expired":return e.reason??"审批已到期"}}export class RuntimeProtocolAdapter{service;connection;clientRequests;responderId;unsubscribe;unsubscribeFatalError;unsubscribeUserInput;settlementTasks=new Set;detachResponder;initialized=!1;closing=!1;transportFailed=!1;controlsService=!1;protocolVersion;unsubscribeReasoningText;capabilityRevision;capabilityMethods;capabilityResult;replayGates=new Map;eventSequence=0;closePromise;constructor(e,i,s){if(x.has(e))throw new S(t.capabilityUnavailable,"当前 RuntimeService 已绑定 Runtime Protocol Adapter");x.add(e),this.controlsService=!0,this.service=e,this.connection=i,this.clientRequests=s,this.responderId=A();try{this.unsubscribe=e.onEvent(e=>this.handleServiceEvent(e))}catch(e){throw this.releaseServiceControl(),e}try{this.unsubscribeUserInput=e.onUserInputInteraction(e=>this.handleUserInputInteraction(e))}catch(e){throw this.unsubscribe(),this.releaseServiceControl(),e}try{this.unsubscribeFatalError=e.onFatalError(()=>this.closeBrokenTransport())}catch(e){throw this.unsubscribeUserInput(),this.unsubscribe(),this.releaseServiceControl(),e}}dispatchEventResume(e){if(!this.initialized)throw new S(t.initializeRequired,"调用 Runtime Protocol 方法前必须先完成 initialize");if("1.3"!==this.protocolVersion&&"1.4"!==this.protocolVersion&&"1.5"!==this.protocolVersion&&"1.6"!==this.protocolVersion)throw new S(t.capabilityUnavailable,`Runtime Protocol ${String(this.protocolVersion)} 不支持方法:${e.method}`);const i=I[s.runtimeEventsResume].params.parse(e.params);if(this.replayGates.has(i.threadId))throw new S(t.threadBusy,`Thread "${i.threadId}" 已有进行中的 Runtime Event replay`,{retryable:!0});const r={threadId:i.threadId,buffered:[],bufferedBytes:0};this.replayGates.set(i.threadId,r);try{const e=this.service.resumeEvents(i);for(const t of e.events){const e={protocolVersion:"1.6",runtimeInstanceId:this.service.runtimeInstanceId,sequence:this.eventSequence,timestamp:t.timestamp,threadId:i.threadId,...void 0===t.turnId?{}:{turnId:q.parse(t.turnId)},durability:"durable",eventId:t.eventId,cursor:t.cursor,event:g.parse(t.event)};if(!this.sendEvent(e))throw new Error("Runtime Event replay transport write failed")}return{result:{throughCursor:e.throughCursor,replayedCount:e.replayedCount},afterResponse:e=>{e?this.flushReplayGate(r):this.releaseReplayGate(r)}}}catch(e){throw this.releaseReplayGate(r),e}}handles(e){return u(r,e)}handleResponse(e){if(void 0===this.protocolVersion||!l(this.protocolVersion).serverRequests||void 0===this.detachResponder)return!1;return T(this.clientRequests).handleResponseForAttachment(this.detachResponder,e)??this.clientRequests.handleResponse(this.responderId,e)}async dispatch(e){return e.method===s.runtimeEventsResume?this.dispatchEventResume(e):e.method===s.clientCapabilitiesSet?this.dispatchClientCapabilitiesSet(e):{result:await this.dispatchValue(e)}}dispatchClientCapabilitiesSet(e){if(!this.initialized)throw new S(t.initializeRequired,"调用 Runtime Protocol 方法前必须先完成 initialize");if(void 0===this.protocolVersion||!l(this.protocolVersion).serverRequestCapabilityNegotiation)throw new S(t.capabilityUnavailable,`Runtime Protocol ${String(this.protocolVersion)} 不支持 capability negotiation:${e.method}`);return this.setClientCapabilities(h.parse(e.params))}async dispatchValue(e){if(!this.handles(e.method))throw new S(t.capabilityUnavailable,`未知 Runtime Protocol 方法:${e.method}`);if(e.method===s.initialize){if(this.initialized)throw new S(t.capabilityUnavailable,"当前连接已完成 initialize,不能重新协商 Runtime Protocol");const i=I[s.initialize].params.parse(e.params),r=this.service.initialize(i);if(this.protocolVersion=r.protocolVersion,l(r.protocolVersion).serverRequests){const e=l(r.protocolVersion).serverRequestCapabilityNegotiation;if(this.detachResponder=this.clientRequests.attachResponder({id:this.responderId,scopeId:r.runtimeInstanceId,send:e=>this.connection.send(e),close:()=>this.connection.close()},{acceptedServerRequestMethods:e?[]:p(r.protocolVersion).serverRequestMethods,capabilitiesAcknowledged:!e}),e){if(!(T(this.clientRequests).beginCapabilityNegotiationForAttachment(this.detachResponder)??this.clientRequests.beginResponderCapabilityNegotiation(this.responderId)))throw new S(t.capabilityUnavailable,"Runtime 客户端 responder 无法进入 capability negotiation")}}return this.initialized=!0,r}if(!this.initialized)throw new S(t.initializeRequired,"调用 Runtime Protocol 方法前必须先完成 initialize");if(void 0===this.protocolVersion||!u(this.protocolVersion,e.method))throw new S(t.capabilityUnavailable,`Runtime Protocol ${String(this.protocolVersion)} 不支持方法:${e.method}`);if(e.method===s.approvalRespond&&void 0!==this.protocolVersion&&!l(this.protocolVersion).clientApprovalResponses)throw new S(t.capabilityUnavailable,"当前协商协议的审批只能通过 approval.request 响应完成");switch(e.method){case s.reasoningTextSubscribe:return I[s.reasoningTextSubscribe].params.parse(e.params),this.unsubscribeReasoningText??=this.service.subscribeReasoningText(e=>this.handleServiceEvent(e)),{subscribed:void 0!==this.unsubscribeReasoningText};case s.threadList:return this.service.listThreads(I[s.threadList].params.parse(e.params));case s.threadCreate:return this.service.createThread(I[s.threadCreate].params.parse(e.params));case s.threadOpen:return this.projectThreadSnapshot(await this.service.openThread(I[s.threadOpen].params.parse(e.params)));case s.threadSnapshot:{const t=m(this.protocolVersion,s.threadSnapshot,e.params),i=("1.3"===this.protocolVersion||"1.4"===this.protocolVersion||"1.5"===this.protocolVersion||"1.6"===this.protocolVersion)&&"recovery"in t&&!0===t.recovery;return this.projectThreadSnapshot(this.service.snapshotThread({threadId:t.threadId,...void 0===t.messageBeforeSequence?{}:{messageBeforeSequence:t.messageBeforeSequence},...void 0===t.operationBeforeSequence?{}:{operationBeforeSequence:t.operationBeforeSequence},limit:t.limit}),i)}case s.threadRename:return this.service.renameThread(I[s.threadRename].params.parse(e.params));case s.threadDelete:return this.service.deleteThread(I[s.threadDelete].params.parse(e.params));case s.threadDetach:return this.service.detachThread(I[s.threadDetach].params.parse(e.params));case s.threadCapabilities:return this.service.threadCapabilities(I[s.threadCapabilities].params.parse(e.params));case s.turnStart:return this.service.startTurn(m(this.protocolVersion,s.turnStart,e.params));case s.turnCancel:return this.service.cancelTurn(I[s.turnCancel].params.parse(e.params));case s.approvalRespond:return this.service.respondApproval(m(this.protocolVersion,s.approvalRespond,e.params));case s.approvalPreview:return this.service.getApprovalPreview(I[s.approvalPreview].params.parse(e.params));case s.operationGet:{const t=this.service.getOperation(I[s.operationGet].params.parse(e.params));return{operation:null===t.operation?null:y(this.protocolVersion,t.operation)}}case s.operationResultGet:return this.service.getOperationResult(I[s.operationResultGet].params.parse(e.params));case s.attachmentStage:return this.service.stageAttachment(I[s.attachmentStage].params.parse(e.params));case s.attachmentChunk:return this.service.appendAttachmentChunk(I[s.attachmentChunk].params.parse(e.params));case s.attachmentCommit:return this.service.commitAttachment(I[s.attachmentCommit].params.parse(e.params));case s.attachmentRelease:return this.service.releaseAttachment(I[s.attachmentRelease].params.parse(e.params));case s.runtimeEventsResume:throw new Error("runtime.events.resume requires the response-barrier dispatch path");case s.clientCapabilitiesSet:throw new Error("client.capabilities.set requires the response-barrier dispatch path")}}async close(){this.closePromise??=this.performClose(),await this.closePromise}disposeConstructionFailure(){this.closing=!0,this.unsubscribeReasoningText?.(),this.unsubscribeFatalError(),this.unsubscribe(),this.unsubscribeUserInput(),this.releaseServiceControl()}releaseServiceControl(){this.controlsService&&(x.delete(this.service),this.controlsService=!1)}async performClose(){for(this.closing=!0,this.replayGates.clear(),this.service.setUserInputAvailable(!1),this.detachResponder?.(),this.detachResponder=void 0;this.settlementTasks.size>0;)await Promise.allSettled([...this.settlementTasks]);this.unsubscribeReasoningText?.(),this.unsubscribeFatalError(),this.unsubscribe(),this.unsubscribeUserInput()}handleServiceEvent(e){if(!this.initialized||this.closing||void 0===this.protocolVersion)return;const t=this.replayGates.get(e.threadId);void 0===t?this.deliverLiveEvent(e):this.bufferReplayLiveEvent(t,e)||this.closeBrokenTransport()}deliverLiveEvent(e){if(!this.initialized||this.closing||void 0===this.protocolVersion)return!1;const t=l(this.protocolVersion);return t.serverRequests&&"approval.resolved"===e.event.type&&this.clientRequests.cancel(e.event.approvalId,B(e.event.resolution)),t.serverRequests&&"approval.required"===e.event.type&&this.requestApproval(e.threadId,e.event.approval),this.sendEvent(e)}sendEvent(e){if(void 0===this.protocolVersion)return!1;if(!l(this.protocolVersion).approvalResolvedEvents&&"approval.resolved"===e.event.type)return!0;const t={...e,sequence:Math.max(this.eventSequence,e.sequence)};this.eventSequence=t.sequence+1;const s=R(this.protocolVersion,t);try{return this.connection.send({jsonrpc:"2.0",method:i,params:s}),!0}catch{return this.closeBrokenTransport(),!1}}bufferReplayLiveEvent(e,t){const i=Buffer.byteLength(JSON.stringify(t),"utf8");return e.buffered.length>=z||e.bufferedBytes+i>G?(this.releaseReplayGate(e),!1):(e.buffered.push(t),e.bufferedBytes+=i,!0)}flushReplayGate(e){if(this.replayGates.get(e.threadId)!==e)return;let t=0;for(;t<e.buffered.length;){const i=e.buffered[t];if(t+=1,void 0!==i&&!this.deliverLiveEvent(i))return void this.releaseReplayGate(e)}this.releaseReplayGate(e)}releaseReplayGate(e){this.replayGates.get(e.threadId)===e&&this.replayGates.delete(e.threadId),e.buffered.length=0,e.bufferedBytes=0}closeBrokenTransport(){if(!this.closing){this.transportFailed=!0,this.closing=!0,this.replayGates.clear(),this.service.setUserInputAvailable(!1),this.detachResponder?.(),this.detachResponder=void 0,this.unsubscribeReasoningText?.(),this.unsubscribeFatalError(),this.unsubscribe(),this.unsubscribeUserInput();try{this.connection.close()}catch{}}}projectThreadSnapshot(e,i=!1){const s=this.protocolVersion;if(void 0===s)throw new S(t.initializeRequired,"投影 Thread Snapshot 前必须先完成 initialize");let r=[];if(!i&&l(s).serverRequestCapabilityNegotiation){if(void 0===this.detachResponder)throw new S(t.capabilityUnavailable,"Runtime Protocol 1.2 responder 已失效");const i=T(this.clientRequests).getPendingInteractionProjectionsForAttachment(this.detachResponder,e.thread.id)??this.clientRequests.getPendingInteractionProjections(this.responderId,e.thread.id);if(void 0===i)throw new S(t.capabilityUnavailable,"Runtime Protocol 1.2 responder attachment 已失效");r=i}if(i){const t=e=>e?.slice(0,c),i=t(e.thread.title),r=t(e.thread.model);return f(s,{...e,thread:{...e.thread,...void 0===i?{}:{title:i},...void 0===r?{}:{model:r}},messages:{items:[],nextBeforeSequence:null},operations:{items:[],nextBeforeSequence:null},pendingApprovals:[],pendingInteractions:[],recoveryProjection:!0})}return f(s,{...e,pendingInteractions:r})}handleUserInputInteraction(e){"settled"!==e.type?!this.closing&&this.initialized&&void 0!==this.protocolVersion&&l(this.protocolVersion).serverRequestCapabilityNegotiation?this.requestUserInput(e):this.service.cancelPendingUserInput(e.requestId,E):this.clientRequests.cancel(k(e.requestId),e.reason)}requestUserInput(t){const i=this.protocolVersion;if(void 0===i||!l(i).serverRequestCapabilityNegotiation)return void this.service.cancelPendingUserInput(t.requestId,E);const s={interactionId:d.parse(e()),threadId:t.threadId,turnId:t.turnId,expiresAt:t.expiresAt,sensitivity:"normal",...t.form};let r;try{r=this.clientRequests.request(n.userInputRequest,s,{key:k(t.requestId),scopeId:this.service.runtimeInstanceId,eligibleResponderId:this.responderId,protocolVersion:i,expiresAt:t.expiresAt})}catch{return void this.service.cancelPendingUserInput(t.requestId,E)}const a=r.result.then(e=>{try{const i=v(s,e);this.service.resolvePendingUserInput(t.requestId,i)}catch{this.service.cancelPendingUserInput(t.requestId,"客户端返回的用户输入不符合原始表单约束")}},e=>{const i=e instanceof P?"用户输入请求已超时":e instanceof V?e.reason:E;this.service.cancelPendingUserInput(t.requestId,i)});this.trackSettlement(a)}requestApproval(i,s){const r={threadId:i,turnId:s.turnId,approvalId:s.id};let a;try{const t=this.protocolVersion;if(void 0===t||"1.0"===t)throw new V("当前协议不支持 Server Request");const o=this.service.getPendingApprovalExpiresAt(r),c=l(t).serverRequestCapabilityNegotiation,h=c?(()=>{if(void 0===o)throw new V("Runtime Protocol 1.2 审批请求缺少绝对 expiresAt deadline");return o})():void 0,p=c?{interactionId:d.parse(e()),threadId:i,turnId:s.turnId,expiresAt:h,sensitivity:"normal",approval:s}:{threadId:i,approval:s};a=this.clientRequests.request(n.approvalRequest,p,{key:s.id,scopeId:this.service.runtimeInstanceId,eligibleResponderId:this.responderId,approvalId:s.id,protocolVersion:t,...void 0===h?{}:{expiresAt:h}})}catch{const e=Promise.resolve().then(()=>this.service.failPendingApprovalInteraction(r,U)).then(()=>{});return void this.trackSettlement(e)}const o=a.result.then(async e=>{const i="approve"===e.decision?{decision:"approve"}:{decision:"reject",...void 0!==e.reason?{reason:e.reason}:{}};try{this.service.resolvePendingApproval(r,i)}catch(e){e instanceof S&&e.rollCode===t.approvalNotFound||await this.service.failPendingApprovalInteraction(r,U)}},async e=>{if(this.closing&&!this.transportFailed)return;if(e instanceof P)return void await this.service.failPendingApprovalInteraction(r,"审批请求已到期",{status:"expired",reason:"审批请求已到期"});const t=e instanceof V?e.reason:U;await this.service.failPendingApprovalInteraction(r,t)});this.trackSettlement(o)}setClientCapabilities(e){if(void 0===this.protocolVersion||!l(this.protocolVersion).serverRequestCapabilityNegotiation||void 0===this.detachResponder)throw new S(t.capabilityUnavailable,"client.capabilities.set 仅可用于支持 capability negotiation 的 Runtime Protocol");const i=[...e.serverRequestMethods].sort();if(void 0!==this.capabilityRevision){const s=e.revision===this.capabilityRevision,r=i.length===this.capabilityMethods?.length&&i.every((e,t)=>e===this.capabilityMethods?.[t]);if(s&&r&&void 0!==this.capabilityResult)return{result:this.capabilityResult};if(e.revision<=this.capabilityRevision)throw new S(t.capabilityRevisionConflict,`Capability revision ${String(e.revision)} 与当前 revision ${String(this.capabilityRevision)} 冲突`)}const s=b(e),r=`Runtime 客户端已在 capability revision ${String(e.revision)} 撤销处理能力`,a=T(this.clientRequests),o=a.setServerRequestMethodsForAttachment(this.detachResponder,s.acceptedServerRequestMethods,r)??a.setServerRequestMethodsForResponder(this.responderId,s.acceptedServerRequestMethods,r);if(!1===o)throw new S(t.capabilityUnavailable,"Runtime 客户端 responder 已失效");return this.service.setUserInputAvailable(s.acceptedServerRequestMethods.includes(n.userInputRequest)),this.capabilityRevision=e.revision,this.capabilityMethods=i,this.capabilityResult=s,{result:s,afterResponse:e=>{e&&o()}}}trackSettlement(e){this.settlementTasks.add(e),e.finally(()=>this.settlementTasks.delete(e)).catch(()=>{})}}
@@ -1 +1 @@
1
- import{RUNTIME_ERROR_CODES as e,jsonValueSchema as s}from"@roll-agent/protocol";import{createSafeCapabilitySnapshot as t}from"../engine/capability-manifest.js";import{isPersistedToolExecutionRecord as o}from"../tool-bridge/tool-execution-record.js";import{RuntimeServiceError as r}from"../service/runtime-service.js";import{RuntimeClientRequestCoordinator as i}from"./runtime-client-request-coordinator.js";import{RuntimeProtocolAdapter as n}from"./runtime-protocol-adapter.js";import{EVENT_NOTIFICATION as a,RpcMethod as c,abortParamsSchema as d,approveParamsSchema as l,capabilitiesParamsSchema as u,closeParamsSchema as h,compactParamsSchema as p,createParamsSchema as m,isRequest as f,messagesParamsSchema as v,rejectParamsSchema as w,resumeParamsSchema as g,sendParamsSchema as R,toolExecutionsParamsSchema as I}from"./protocol.js";function y(e){return e instanceof Error?e.message:String(e)}class MethodNotFoundError extends Error{}class RuntimeTransportWriteError extends Error{}function S(e){return e instanceof Error&&"ZodError"===e.name&&"issues"in e&&Array.isArray(e.issues)}function C(e,t){if(e instanceof r){const t=s.safeParse(e.details);return{code:-32e3,message:e.message,data:{rollCode:e.rollCode,retryable:e.retryable,...t.success?{details:t.data}:{}}}}return S(e)?{code:-32602,message:"Invalid params",data:{rollCode:"INVALID_PARAMS",retryable:!1}}:e instanceof MethodNotFoundError?{code:-32601,message:e.message}:{code:-32603,message:t?"Internal error":y(e),data:{rollCode:"INTERNAL_ERROR",retryable:!1}}}const b={unselected:"unselected",legacy:"legacy",runtime:"runtime"},E=new Set(Object.values(c));export class RuntimeServer{engine;connection;authorizeRawToolEvidence;sessions=new Map;runtimeService;runtimeClientRequests;protocolAdapter;connectionMode=b.unselected;abortPromise;constructor(e,s,t={}){this.engine=e,this.connection=s,this.authorizeRawToolEvidence=t.authorizeRawToolEvidence,this.runtimeService=t.runtimeService,this.runtimeClientRequests=void 0===t.runtimeService?void 0:t.runtimeClientRequests??new i,this.protocolAdapter=void 0===t.runtimeService||void 0===this.runtimeClientRequests?void 0:new n(t.runtimeService,s,this.runtimeClientRequests);try{this.connection.onMessage(e=>this.handleMessage(e))}catch(e){throw this.protocolAdapter?.disposeConstructionFailure(),e}}async abortAll(){this.abortPromise??=this.performAbortAll(),await this.abortPromise}async performAbortAll(){const e=[...this.sessions.values()];this.sessions.clear();const s=this.protocolAdapter?.close();this.runtimeClientRequests?.cancelAll("Runtime Server 已关闭");try{await Promise.all([...e.map(e=>e.close()),...void 0===s?[]:[s],...void 0===this.runtimeService?[]:[this.runtimeService.close()]])}finally{this.protocolAdapter?.releaseServiceControl()}}handleMessage(e){if(!0===this.protocolAdapter?.handleResponse(e))return;if(!f(e))return;const s=!0===this.protocolAdapter?.handles(e.method);try{this.selectConnectionMode(e.method,s)}catch(t){return void this.sendOrClose({jsonrpc:"2.0",id:e.id,error:C(t,s)})}this.dispatch(e).then(s=>{const t=this.sendOrClose({jsonrpc:"2.0",id:e.id,result:s.result});s.afterResponse?.(t)},t=>{t instanceof RuntimeTransportWriteError||this.sendOrClose({jsonrpc:"2.0",id:e.id,error:C(t,s)})})}sendOrClose(e){try{return this.connection.send(e),!0}catch{try{this.connection.close()}catch{}return!1}}sendNotificationOrThrow(e){if(!this.sendOrClose(e))throw new RuntimeTransportWriteError("Runtime transport write failed")}requireSession(e){const s=this.sessions.get(e);if(!s)throw new Error(`Session "${e}" 不存在`);return s}selectConnectionMode(s,t){if(t){if(this.connectionMode===b.legacy)throw new r(e.capabilityUnavailable,"当前连接已选择 legacy session.* 协议,不能切换到 Runtime Protocol");this.connectionMode=b.runtime}else if(E.has(s)){if(this.connectionMode===b.runtime)throw new r(e.capabilityUnavailable,"当前连接已选择 Runtime Protocol,不能调用 legacy session.* 方法");this.connectionMode=b.legacy}}async dispatch(e){return!0===this.protocolAdapter?.handles(e.method)?this.protocolAdapter.dispatch(e):{result:await this.dispatchLegacy(e)}}async dispatchLegacy(e){switch(e.method){case c.Create:{const s=m.parse(e.params),t=await this.engine.createSession(s.title?{title:s.title}:{});return this.sessions.set(t.id,t),{sessionId:t.id}}case c.Resume:{const s=g.parse(e.params),t=await this.engine.resumeSession(s.threadId);return this.sessions.set(t.id,t),{sessionId:t.id}}case c.Send:{const s=R.parse(e.params),t=this.requireSession(s.sessionId);for await(const e of t.send(s.input))this.sendNotificationOrThrow({jsonrpc:"2.0",method:a,params:{sessionId:s.sessionId,event:"confirmation-required"===e.type?{...e,fullDiff:void 0}:e}});return{status:"completed"}}case c.Approve:{const s=l.parse(e.params);return{resolved:this.requireSession(s.sessionId).approve(s.approvalId)}}case c.Reject:{const s=w.parse(e.params);return{resolved:this.requireSession(s.sessionId).reject(s.approvalId,s.reason)}}case c.Abort:{const s=d.parse(e.params);return{ok:!0,cancelled:this.requireSession(s.sessionId).cancel()}}case c.Close:{const s=h.parse(e.params),t=this.requireSession(s.sessionId);return await t.close(),this.sessions.delete(s.sessionId),{closed:!0}}case c.Messages:{const s=v.parse(e.params);return{messages:this.requireSession(s.sessionId).getMessages()}}case c.ToolExecutions:{const s=I.parse(e.params),t=this.requireSession(s.sessionId);if(s.includeRaw&&!await(this.authorizeRawToolEvidence?.({sessionId:s.sessionId,...void 0!==s.executionId?{executionId:s.executionId}:{}})))throw new Error("Raw Tool evidence access denied by RuntimeServer policy");if(void 0!==s.executionId){const e=t.getToolExecution(s.executionId,s.includeRaw);if(s.includeRaw&&void 0!==e&&!o(e))throw new Error("Raw Tool evidence is unavailable without a durable ledger projection");return{record:e}}const r=t.getToolExecutions({...void 0!==s.afterSequence?{afterSequence:s.afterSequence}:{},...void 0!==s.limit?{limit:s.limit}:{},...void 0!==s.toolCallId?{toolCallId:s.toolCallId}:{}},s.includeRaw);if(s.includeRaw&&r.some(e=>!o(e)))throw new Error("Raw Tool evidence is unavailable without a durable ledger projection");return{records:r}}case c.Capabilities:{const s=u.parse(e.params),o=this.requireSession(s.sessionId);return t(o.getCapabilityManifest(),o.getCapabilityTurnContext())}case c.Compact:{const s=p.parse(e.params),t=this.requireSession(s.sessionId);for await(const e of t.compact("manual"))this.sendNotificationOrThrow({jsonrpc:"2.0",method:a,params:{sessionId:s.sessionId,event:e}});return{status:"completed"}}default:throw new MethodNotFoundError(`Method not found: ${e.method}`)}}}
1
+ import{RUNTIME_ERROR_CODES as e,jsonValueSchema as s}from"@roll-agent/protocol";import{createSafeCapabilitySnapshot as t}from"../engine/capability-manifest.js";import{isPersistedToolExecutionRecord as o}from"../tool-bridge/tool-execution-record.js";import{RuntimeServiceError as r}from"../service/runtime-service.js";import{RuntimeClientRequestCoordinator as i}from"./runtime-client-request-coordinator.js";import{RuntimeProtocolAdapter as n}from"./runtime-protocol-adapter.js";import{EVENT_NOTIFICATION as a,RpcMethod as c,abortParamsSchema as d,approveParamsSchema as l,capabilitiesParamsSchema as u,closeParamsSchema as p,compactParamsSchema as h,createParamsSchema as m,isRequest as f,messagesParamsSchema as v,rejectParamsSchema as w,resumeParamsSchema as g,sendParamsSchema as y,toolExecutionsParamsSchema as R}from"./protocol.js";function I(e){return e instanceof Error?e.message:String(e)}function S(e){return e.map(e=>{const{providerOptions:s,...t}=e;if("string"==typeof t.content)return t;const o=t.content.filter(e=>"reasoning"!==e.type).map(e=>{if(!("providerOptions"in e))return e;const{providerOptions:s,...t}=e;return t});return{...t,content:o}}).filter(e=>!("assistant"===e.role&&Array.isArray(e.content)&&0===e.content.length))}class MethodNotFoundError extends Error{}class RuntimeTransportWriteError extends Error{}function C(e){return e instanceof Error&&"ZodError"===e.name&&"issues"in e&&Array.isArray(e.issues)}function b(e,t){if(e instanceof r){const t=s.safeParse(e.details);return{code:-32e3,message:e.message,data:{rollCode:e.rollCode,retryable:e.retryable,...t.success?{details:t.data}:{}}}}return C(e)?{code:-32602,message:"Invalid params",data:{rollCode:"INVALID_PARAMS",retryable:!1}}:e instanceof MethodNotFoundError?{code:-32601,message:e.message}:{code:-32603,message:t?"Internal error":I(e),data:{rollCode:"INTERNAL_ERROR",retryable:!1}}}const A={unselected:"unselected",legacy:"legacy",runtime:"runtime"},E=new Set(Object.values(c));export class RuntimeServer{engine;connection;authorizeRawToolEvidence;sessions=new Map;runtimeService;runtimeClientRequests;protocolAdapter;connectionMode=A.unselected;abortPromise;constructor(e,s,t={}){this.engine=e,this.connection=s,this.authorizeRawToolEvidence=t.authorizeRawToolEvidence,this.runtimeService=t.runtimeService,this.runtimeClientRequests=void 0===t.runtimeService?void 0:t.runtimeClientRequests??new i,this.protocolAdapter=void 0===t.runtimeService||void 0===this.runtimeClientRequests?void 0:new n(t.runtimeService,s,this.runtimeClientRequests);try{this.connection.onMessage(e=>this.handleMessage(e))}catch(e){throw this.protocolAdapter?.disposeConstructionFailure(),e}}async abortAll(){this.abortPromise??=this.performAbortAll(),await this.abortPromise}async performAbortAll(){const e=[...this.sessions.values()];this.sessions.clear();const s=this.protocolAdapter?.close();this.runtimeClientRequests?.cancelAll("Runtime Server 已关闭");try{await Promise.all([...e.map(e=>e.close()),...void 0===s?[]:[s],...void 0===this.runtimeService?[]:[this.runtimeService.close()]])}finally{this.protocolAdapter?.releaseServiceControl()}}handleMessage(e){if(!0===this.protocolAdapter?.handleResponse(e))return;if(!f(e))return;const s=!0===this.protocolAdapter?.handles(e.method);try{this.selectConnectionMode(e.method,s)}catch(t){return void this.sendOrClose({jsonrpc:"2.0",id:e.id,error:b(t,s)})}this.dispatch(e).then(s=>{const t=this.sendOrClose({jsonrpc:"2.0",id:e.id,result:s.result});s.afterResponse?.(t)},t=>{t instanceof RuntimeTransportWriteError||this.sendOrClose({jsonrpc:"2.0",id:e.id,error:b(t,s)})})}sendOrClose(e){try{return this.connection.send(e),!0}catch{try{this.connection.close()}catch{}return!1}}sendNotificationOrThrow(e){if(!this.sendOrClose(e))throw new RuntimeTransportWriteError("Runtime transport write failed")}requireSession(e){const s=this.sessions.get(e);if(!s)throw new Error(`Session "${e}" 不存在`);return s}selectConnectionMode(s,t){if(t){if(this.connectionMode===A.legacy)throw new r(e.capabilityUnavailable,"当前连接已选择 legacy session.* 协议,不能切换到 Runtime Protocol");this.connectionMode=A.runtime}else if(E.has(s)){if(this.connectionMode===A.runtime)throw new r(e.capabilityUnavailable,"当前连接已选择 Runtime Protocol,不能调用 legacy session.* 方法");this.connectionMode=A.legacy}}async dispatch(e){return!0===this.protocolAdapter?.handles(e.method)?this.protocolAdapter.dispatch(e):{result:await this.dispatchLegacy(e)}}async dispatchLegacy(e){switch(e.method){case c.Create:{const s=m.parse(e.params),t=await this.engine.createSession(s.title?{title:s.title}:{});return this.sessions.set(t.id,t),{sessionId:t.id}}case c.Resume:{const s=g.parse(e.params),t=await this.engine.resumeSession(s.threadId);return this.sessions.set(t.id,t),{sessionId:t.id}}case c.Send:{const s=y.parse(e.params),t=this.requireSession(s.sessionId);for await(const e of t.send(s.input))"reasoning-delta"!==e.type&&this.sendNotificationOrThrow({jsonrpc:"2.0",method:a,params:{sessionId:s.sessionId,event:"confirmation-required"===e.type?{...e,fullDiff:void 0}:e}});return{status:"completed"}}case c.Approve:{const s=l.parse(e.params);return{resolved:this.requireSession(s.sessionId).approve(s.approvalId)}}case c.Reject:{const s=w.parse(e.params);return{resolved:this.requireSession(s.sessionId).reject(s.approvalId,s.reason)}}case c.Abort:{const s=d.parse(e.params);return{ok:!0,cancelled:this.requireSession(s.sessionId).cancel()}}case c.Close:{const s=p.parse(e.params),t=this.requireSession(s.sessionId);return await t.close(),this.sessions.delete(s.sessionId),{closed:!0}}case c.Messages:{const s=v.parse(e.params);return{messages:S(this.requireSession(s.sessionId).getMessages())}}case c.ToolExecutions:{const s=R.parse(e.params),t=this.requireSession(s.sessionId);if(s.includeRaw&&!await(this.authorizeRawToolEvidence?.({sessionId:s.sessionId,...void 0!==s.executionId?{executionId:s.executionId}:{}})))throw new Error("Raw Tool evidence access denied by RuntimeServer policy");if(void 0!==s.executionId){const e=t.getToolExecution(s.executionId,s.includeRaw);if(s.includeRaw&&void 0!==e&&!o(e))throw new Error("Raw Tool evidence is unavailable without a durable ledger projection");return{record:e}}const r=t.getToolExecutions({...void 0!==s.afterSequence?{afterSequence:s.afterSequence}:{},...void 0!==s.limit?{limit:s.limit}:{},...void 0!==s.toolCallId?{toolCallId:s.toolCallId}:{}},s.includeRaw);if(s.includeRaw&&r.some(e=>!o(e)))throw new Error("Raw Tool evidence is unavailable without a durable ledger projection");return{records:r}}case c.Capabilities:{const s=u.parse(e.params),o=this.requireSession(s.sessionId);return t(o.getCapabilityManifest(),o.getCapabilityTurnContext())}case c.Compact:{const s=h.parse(e.params),t=this.requireSession(s.sessionId);for await(const e of t.compact("manual"))this.sendNotificationOrThrow({jsonrpc:"2.0",method:a,params:{sessionId:s.sessionId,event:e}});return{status:"completed"}}default:throw new MethodNotFoundError(`Method not found: ${e.method}`)}}}
@@ -0,0 +1,11 @@
1
+ /** Keep the context of earlier chunks so a credential split across deltas is redacted as one value. */
2
+ export declare class ReasoningDisplayBuffer {
3
+ private raw;
4
+ private sent;
5
+ private stopped;
6
+ private lastScanLength;
7
+ private lastScanAt;
8
+ append(delta: string): string;
9
+ finish(): string;
10
+ private advance;
11
+ }
@@ -0,0 +1 @@
1
+ import{redactSecretText as t}from"../tool-bridge/tool-execution-record.js";const s=16384,e=128,n=32,i="\n…(后续内容已省略)";export class ReasoningDisplayBuffer{raw="";sent="";stopped=!1;lastScanLength=0;lastScanAt=0;append(i){if(this.stopped)return"";const a=s-this.raw.length;this.raw+=i.slice(0,a);const h=i.length>a;if(!h&&!/[\s。!?]/u.test(i))return"";const r=performance.now();if(!h&&this.raw.length>e&&this.raw.length-this.lastScanLength<e&&r-this.lastScanAt<n)return"";this.lastScanLength=this.raw.length,this.lastScanAt=r;const c=t(this.raw),o=/(?:-----BEGIN[ A-Z0-9-]*|\bbearer\s+)$/iu.exec(c);let l=o?.index??c.length;for(;l>this.sent.length&&!/[\s。!?]/u.test(c.charAt(l-1));)l--;return this.advance(c.slice(0,l),h)}finish(){return this.stopped?"":this.advance(t(this.raw))}advance(t,s=!1){const e=t.startsWith(this.sent),n=e?t.slice(this.sent.length):"";return s||!e?(this.stopped=!0,n+i):(this.sent=t,n)}}
@@ -2,6 +2,7 @@ import { RUNTIME_METHODS, approvalIdSchema, type ApprovalResolution, type Initia
2
2
  import type { AgentSession } from "../engine/agent-session.ts";
3
3
  import { AttachmentStore } from "./attachment-store.ts";
4
4
  import type { SessionUserInputRequestId } from "../interaction/user-input-interaction-manager.ts";
5
+ import type { ReasoningPresentation } from "../types/events.ts";
5
6
  import { ThreadStore, type StoredRuntimeEvent } from "../store/thread-store.ts";
6
7
  type RollErrorCode = RuntimeProtocolErrorDataV14["rollCode"];
7
8
  export type RuntimeServiceSession = Pick<AgentSession, "id" | "send" | "approve" | "reject" | "cancel" | "close" | "getCapabilityManifest" | "getCapabilityTurnContext"> & Partial<Pick<AgentSession, "setUserInputAvailable" | "resolveUserInput" | "cancelUserInput">>;
@@ -17,6 +18,8 @@ export interface RuntimeServiceOptions {
17
18
  readonly runtimeVersion?: string;
18
19
  readonly maxFrameBytes?: number;
19
20
  readonly idempotencyCacheEntries?: number;
21
+ /** Accept only source-classified deltas of this kind. Text requires a separate local subscription. */
22
+ readonly providerReasoning?: ReasoningPresentation["kind"];
20
23
  /**
21
24
  * Optional host-controlled projection. Raw model reasoning is never sent to public clients.
22
25
  * Supplying this enables the `reasoning-summary` capability.
@@ -85,6 +88,8 @@ export declare class RuntimeService {
85
88
  private readonly maxFrameBytes;
86
89
  private readonly idempotencyCacheEntries;
87
90
  private readonly reasoningSummaryProjector;
91
+ private readonly providerReasoning;
92
+ private reasoningTextSubscription;
88
93
  private readonly attachmentStore;
89
94
  private readonly sessions;
90
95
  private readonly activeTurns;
@@ -101,6 +106,7 @@ export declare class RuntimeService {
101
106
  private userInputAvailable;
102
107
  constructor(engine: RuntimeServiceEngine, store: ThreadStore, options?: RuntimeServiceOptions);
103
108
  initialize(params: InitializeParams): InitializeResult;
109
+ subscribeReasoningText(listener: (event: RuntimeEventEnvelopeV16) => void): (() => void) | undefined;
104
110
  onEvent(listener: (event: RuntimeEventEnvelopeV16) => void): () => void;
105
111
  onFatalError(listener: (error: unknown) => void): () => void;
106
112
  onUserInputInteraction(listener: (event: RuntimeUserInputInteractionEvent) => void): () => void;
@@ -142,6 +148,7 @@ export declare class RuntimeService {
142
148
  private rememberSession;
143
149
  private emit;
144
150
  private notifyFatalError;
151
+ private createTurnReasoningDisplay;
145
152
  private driveTurn;
146
153
  private findTurnOwner;
147
154
  private settleTurnOwner;
@@ -1 +1 @@
1
- import{createHash as e,randomUUID as t}from"node:crypto";import{APPROVAL_DIFF_PREVIEW_KEY as r,initializeResultSchema as s,APPROVAL_EXPLANATION_PREVIEW_KEY as n,RUNTIME_ERROR_CODES as i,RUNTIME_FEATURES_V13 as a,RUNTIME_METHODS as o,RUNTIME_PROTOCOL_VERSION as d,RUNTIME_V14_MAX_ATTACHMENT_BYTES as u,RUNTIME_V14_MAX_ATTACHMENT_CHUNK_BYTES as h,RUNTIME_V14_MAX_STAGED_ATTACHMENTS as c,RUNTIME_V14_MAX_TURN_ATTACHMENTS as l,SUPPORTED_RUNTIME_PROTOCOL_VERSIONS as p,approvalExplanationSchema as m,approvalIdSchema as I,normalizeUserInputResultForForm as v,operationIdSchema as g,parseLatestRuntimeMethodResult as f,runtimeDurableEventV16Schema as y,runtimeEphemeralEventV13Schema as T,runtimeInstanceIdSchema as A,runtimeProtocolVersionSchema as w,streamIdSchema as q,threadIdSchema as S,userInputFormSchema as x}from"@roll-agent/protocol";import{AttachmentStore as R}from"./attachment-store.js";import{createSafeCapabilitySnapshot as E}from"../engine/capability-manifest.js";import{isSensitiveFieldName as O,redactSecretText as b,toRedactedToolExecutionRecordSummary as P}from"../tool-bridge/tool-execution-record.js";import{RuntimeEventCursorExpiredError as C,RuntimeEventCursorGapError as U,ThreadStore as N}from"../store/thread-store.js";const F=4194304,k=500,j=1e4,B=16e3,M=64,D=128,V=16,$=new Set(["_meta","authorization","cookie","password","provideroptions","raw","secret","token"]);export class RuntimeServiceError extends Error{rollCode;retryable;details;constructor(e,t,r={}){super(t),this.name="RuntimeServiceError",this.rollCode=e,this.retryable=r.retryable??!1,this.details=r.details}}function L(t){const r=JSON.stringify(t);if(void 0===r)throw new RuntimeServiceError(i.invalidParams,"无法为 mutation 请求生成稳定指纹");return e("sha256").update(r).digest("hex")}export class MutationRequestCache{maxEntries;inFlight=new Map;settled=new Map;constructor(e){if(!Number.isInteger(e)||e<1)throw new Error("idempotencyCacheEntries must be a positive integer");this.maxEntries=e}run(e,t,r,s){const n=L(r),i=this.inFlight.get(e);if(void 0!==i)return this.assertMatchingRequest(e,t,n,i),i.response.then(e=>f(t,e));const a=this.settled.get(e);if(void 0!==a)return this.assertMatchingRequest(e,t,n,a),this.settled.delete(e),this.settled.set(e,a),a.response.then(e=>f(t,e));const o=Promise.resolve().then(s),d={method:t,fingerprint:n,response:o};return this.inFlight.set(e,d),o.then(()=>{this.settle(e,d)},()=>{this.settle(e,d)}),o}clear(){this.inFlight.clear(),this.settled.clear()}assertMatchingRequest(e,t,r,s){if(s.method!==t||s.fingerprint!==r)throw new RuntimeServiceError(i.invalidParams,`requestId "${e}" 已用于不同请求`)}settle(e,t){if(this.inFlight.get(e)===t)for(this.inFlight.delete(e),this.settled.set(e,t);this.settled.size>this.maxEntries;){const e=this.settled.keys().next().value;if(void 0===e)return;this.settled.delete(e)}}}function _(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function z(e,t,r=0){if(void 0!==t&&($.has(t.toLowerCase())||O(t)))return"[redacted]";if(r>=V)return"[nested value omitted]";if(null===e||"boolean"==typeof e)return e;if("string"==typeof e){const t=b(e);return t.length<=B?t:`${t.slice(0,B)}\n[value clipped]`}if("number"==typeof e)return Number.isFinite(e)?e:String(e);if(Array.isArray(e)){const t=e.slice(0,M).map(e=>z(e,void 0,r+1));return e.length>M&&t.push(`[${String(e.length-M)} items omitted]`),t}if(_(e)){const t={};for(const[s,n]of Object.entries(e).slice(0,D))void 0!==n&&(t[s]=z(n,s,r+1));return Object.keys(e).length>D&&(t._omitted=`${String(Object.keys(e).length-D)} keys omitted`),t}return void 0===e?null:String(e)}function W(e){return e instanceof Error?e.message:String(e)}function G(e){const t=e.content;return"string"==typeof t?t:Array.isArray(t)?t.flatMap(e=>_(e)&&"text"===e.type&&"string"==typeof e.text?[e.text]:[]).join(""):""}function J(e){const t=e.endsWith("==")?2:e.endsWith("=")?1:0;return Math.max(0,3*Math.floor(e.length/4)-t)}function H(e){const t=e.content;return"user"===e.role&&Array.isArray(t)?t.flatMap(e=>_(e)?"file"===e.type&&"string"==typeof e.mediaType&&"string"==typeof e.data?[{type:"attachment",mediaType:e.mediaType,bytes:J(e.data)}]:"image"===e.type&&"string"==typeof e.image?[{type:"attachment",mediaType:"image/*",bytes:J(e.image)}]:[]:[]):[]}function K(e){return S.parse(e)}function Q(e,t){return{id:K(t.id),...void 0!==t.title?{title:t.title}:{},...void 0!==t.model?{model:t.model}:{},createdAt:t.createdAt,updatedAt:t.updatedAt,messageCount:e.countTranscriptMessages(t.id)}}function X(e){if("user"!==e.message.role&&"assistant"!==e.message.role)return;const t=b(G(e.message));return{sequence:e.sequence,role:e.message.role,createdAt:e.createdAt,parts:[...t.length>0?[{type:"text",text:t}]:[],...H(e.message)]}}function Y(e,t={status:"not_provided"}){const r=P(e);return{id:g.parse(r.id),sequence:e.sequence,toolCallId:r.toolCallId,agentName:r.agentName,toolName:r.toolName,createdAt:r.createdAt,outcome:{kind:r.outcome.kind,..."reason"in r.outcome&&void 0!==r.outcome.reason?{reason:r.outcome.reason}:{}},display:z(r.display,void 0),appOutput:t}}function Z(e,t){const s=z(t.input,void 0),i=void 0===t.explanation?void 0:m.safeParse(b(t.explanation)),a=void 0===t.diff?void 0:z(t.diff,void 0),o=_(s)?{...s,...!0===i?.success?{[n]:i.data}:{},...void 0!==a?{[r]:a}:{},...void 0!==t.fullDiff?{fullDiffAvailable:!0}:{}}:s;return{id:I.parse(t.approvalId),turnId:e,agentName:t.agentName,toolName:t.toolName,preview:o,...void 0!==t.reason?{reason:b(t.reason)}:{}}}export class RuntimeService{runtimeInstanceId;engine;store;serverName;serverVersion;runtimeVersion;maxFrameBytes;idempotencyCacheEntries;reasoningSummaryProjector;attachmentStore;sessions=new Map;activeTurns=new Map;activeTurnOwners=new Map;settledTurnOwners=new Map;pendingApprovals=new Map;pendingUserInputs=new Map;listeners=new Set;fatalErrorListeners=new Set;userInputListeners=new Set;mutationRequests;sequence=0;closing=!1;userInputAvailable=!1;constructor(e,r,s={}){this.engine=e,this.store=r,this.serverName=s.serverName??"roll-runtime",this.serverVersion=s.serverVersion??"1.0",this.runtimeVersion=s.runtimeVersion??"development",this.maxFrameBytes=s.maxFrameBytes??F,this.idempotencyCacheEntries=s.idempotencyCacheEntries??j,this.mutationRequests=new MutationRequestCache(this.idempotencyCacheEntries),this.reasoningSummaryProjector=s.reasoningSummaryProjector,this.attachmentStore=s.attachmentStore,this.runtimeInstanceId=A.parse(t())}initialize(e){let t;this.assertOpen();for(const r of e.protocolVersions){const e=w.safeParse(r);if(e.success){t=e.data;break}}if(void 0===t)throw new RuntimeServiceError(i.protocolVersionUnsupported,`不支持客户端协议版本:${e.protocolVersions.join(", ")}`,{details:{supportedVersions:p}});const r=a.filter(e=>"reasoning-summary"!==e||void 0!==this.reasoningSummaryProjector),n={protocolVersion:t,runtimeInstanceId:this.runtimeInstanceId,server:{name:this.serverName,version:this.serverVersion,runtimeVersion:this.runtimeVersion},features:r,limits:{maxFrameBytes:this.maxFrameBytes,maxPageSize:k,idempotencyCacheEntries:this.idempotencyCacheEntries}};if("1.4"===t||"1.5"===t||"1.6"===t){const e=this.attachmentStore?.limits;return s.parse({...n,protocolVersion:t,features:[...r,...void 0!==this.attachmentStore?["attachments"]:[],..."1.5"===t||"1.6"===t?["app-output"]:[]],limits:{...n.limits,eventReplay:!0,maxAttachmentBytes:e?.maxAttachmentBytes??u,maxAttachmentChunkBytes:e?.maxAttachmentChunkBytes??h,maxTurnAttachments:l,maxStagedAttachments:e?.maxStagedAttachments??c}})}return"1.3"===t?{...n,protocolVersion:t,limits:{...n.limits,eventReplay:!0}}:{...n,protocolVersion:t,limits:{...n.limits,eventReplay:!1}}}onEvent(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}onFatalError(e){return this.fatalErrorListeners.add(e),()=>{this.fatalErrorListeners.delete(e)}}onUserInputInteraction(e){return this.userInputListeners.add(e),()=>{this.userInputListeners.delete(e)}}setUserInputAvailable(e){if(this.userInputAvailable!==e){this.userInputAvailable=e,e||this.cancelAllPendingUserInputs("当前客户端已撤销用户输入处理能力");for(const t of this.sessions.values())t.setUserInputAvailable?.(e)}}listThreads(e){this.assertOpen();const t=void 0===e.cursor?0:Number(e.cursor);if(!Number.isSafeInteger(t)||t<0)throw new RuntimeServiceError(i.invalidParams,"thread.list cursor 超出安全整数范围");const r=this.store.listThreads({origin:"interactive"}),s=r.slice(t,t+e.limit).map(e=>Q(this.store,e)),n=t+s.length;return{items:s,nextCursor:n<r.length?String(n):null}}async createThread(e){return this.mutationRequests.run(e.requestId,o.threadCreate,e,async()=>{this.assertOpen();const t=await this.engine.createSession(void 0!==e.title?{title:e.title}:{});return this.rememberSession(t),{thread:Q(this.store,this.requireThread(t.id))}})}async openThread(e){return this.assertOpen(),"scheduled"!==this.requireThread(e.threadId).origin.kind&&await this.requireSession(e.threadId),this.snapshotThread({threadId:e.threadId,limit:100})}snapshotThread(e){this.assertOpen();const t=this.requireThread(e.threadId),r=this.store.listRecentTranscriptMessages(e.threadId,{...void 0!==e.messageBeforeSequence?{beforeSequence:e.messageBeforeSequence}:{},limit:e.limit}),s=this.store.listRecentToolExecutions(e.threadId,{...void 0!==e.operationBeforeSequence?{beforeSequence:e.operationBeforeSequence}:{},limit:e.limit}),n=this.activeTurns.get(e.threadId),i=void 0===n?void 0:{id:n.turnId,status:n.status,startedAt:n.startedAt};return{thread:Q(this.store,t),messages:{items:r.entries.flatMap(e=>{const t=X(e);return void 0===t?[]:[t]}),nextBeforeSequence:r.nextBeforeSequence??null},operations:{items:s.entries.map(t=>Y(t,this.store.getAppOutputDescriptor(e.threadId,t.id))),nextBeforeSequence:s.nextBeforeSequence??null},...void 0!==i?{activeTurn:i}:{},pendingApprovals:[...this.pendingApprovals.values()].filter(t=>t.threadId===e.threadId).map(e=>e.approval),transcriptCompleteness:this.store.getTranscriptCompleteness(e.threadId),eventCursor:this.store.getRuntimeEventCursor(e.threadId),contextRecovery:null}}resumeEvents(e){this.assertOpen(),this.requireThread(e.threadId);try{return this.store.resumeRuntimeEvents(e.threadId,e.afterCursor)}catch(t){if(t instanceof C)throw new RuntimeServiceError(i.eventCursorExpired,"Runtime Event cursor 已超出当前 Thread 的保留窗口,请回退到 thread.snapshot",{details:{threadId:e.threadId}});if(t instanceof U)throw new RuntimeServiceError(i.eventCursorGap,"Runtime Event cursor 与当前 Thread 事件日志不连续,请回退到 thread.snapshot",{details:{threadId:e.threadId}});throw t}}async renameThread(e){return this.mutationRequests.run(e.requestId,o.threadRename,e,()=>(this.assertOpen(),this.requireThread(e.threadId),this.store.updateTitle(e.threadId,e.title),{thread:Q(this.store,this.requireThread(e.threadId))}))}async deleteThread(e){return this.mutationRequests.run(e.requestId,o.threadDelete,e,async()=>{if(this.assertOpen(),this.requireThread(e.threadId),this.activeTurns.has(e.threadId))throw new RuntimeServiceError(i.threadBusy,`Thread "${e.threadId}" 仍有活动 Turn`,{retryable:!0});const t=this.sessions.get(e.threadId);return void 0!==t&&(await t.close(),this.sessions.delete(e.threadId)),this.attachmentStore?.releaseThread(e.threadId),this.store.deleteThread(e.threadId),{deleted:!0}})}async detachThread(e){return this.mutationRequests.run(e.requestId,o.threadDetach,e,async()=>{if(this.assertOpen(),this.requireThread(e.threadId),this.activeTurns.has(e.threadId))return{detached:!1};const t=this.sessions.get(e.threadId);return void 0===t?{detached:!1}:(await t.close(),this.sessions.delete(e.threadId),{detached:!0})})}async threadCapabilities(e){const t=await this.requireSession(e.threadId);return{manifest:z(E(t.getCapabilityManifest(),t.getCapabilityTurnContext()),void 0)}}async startTurn(e){return this.mutationRequests.run(e.requestId,o.turnStart,e,async()=>{if(this.assertOpen(),"scheduled"===this.requireThread(e.threadId).origin.kind)throw new RuntimeServiceError(i.invalidParams,"定时执行会话是只读记录;请基于该次运行创建新对话");const t=this.findTurnOwner(e.turnId,e.threadId);if(void 0!==t){if(t===e.threadId)return{accepted:!0,turnId:e.turnId};throw new RuntimeServiceError(i.turnAlreadyActive,`Turn "${e.turnId}" 已属于另一个 Thread`)}if(this.activeTurns.has(e.threadId))throw new RuntimeServiceError(i.turnAlreadyActive,`Thread "${e.threadId}" 已有活动 Turn`,{retryable:!0});const r=await this.requireSession(e.threadId),s=this.findTurnOwner(e.turnId,e.threadId);if(void 0!==s){if(s===e.threadId)return{accepted:!0,turnId:e.turnId};throw new RuntimeServiceError(i.turnAlreadyActive,`Turn "${e.turnId}" 已属于另一个 Thread`)}if(this.activeTurns.has(e.threadId))throw new RuntimeServiceError(i.turnAlreadyActive,`Thread "${e.threadId}" 已有活动 Turn`,{retryable:!0});const n=this.resolveTurnAttachments(e),a={threadId:e.threadId,turnId:e.turnId,session:r,startedAt:(new Date).toISOString(),status:"running",interactionFailure:void 0};this.activeTurns.set(e.threadId,a),this.activeTurnOwners.set(e.turnId,e.threadId);try{this.emit(e.threadId,e.turnId,{type:"turn.started"})}catch(t){throw this.activeTurns.delete(e.threadId),this.activeTurnOwners.delete(e.turnId),t}return this.driveTurn(a,e.input.text,n).catch(()=>{}),{accepted:!0,turnId:e.turnId}})}async cancelTurn(e){return this.mutationRequests.run(e.requestId,o.turnCancel,e,()=>{this.assertOpen();const t=this.activeTurns.get(e.threadId);if(void 0===t||t.turnId!==e.turnId)throw new RuntimeServiceError(i.turnNotFound,`Turn "${e.turnId}" 不存在或已结束`);t.status="cancelling";let r=!1;try{this.cancelPendingUserInputsForTurn(e.turnId,"Turn 已由客户端取消"),this.cancelPendingApprovalsForTurn(e.turnId,{status:"cancelled",reason:"Turn 已由客户端取消"})}finally{r=t.session.cancel()}return{cancelling:r}})}async respondApproval(e){return this.mutationRequests.run(e.requestId,o.approvalRespond,e,()=>this.resolvePendingApproval(e,"approve"===e.decision?{decision:"approve"}:{decision:"reject",...void 0!==e.reason?{reason:e.reason}:{}}))}resolvePendingApproval(e,t){this.assertOpen();const r=this.requirePendingApproval(e),s="approve"===t.decision?r.session.approve(e.approvalId,t.scope):r.session.reject(e.approvalId,t.reason);if(this.pendingApprovals.delete(e.approvalId),!s)throw this.emitApprovalResolved(r,{status:"cancelled",reason:"审批已失效"}),new RuntimeServiceError(i.approvalNotFound,`Approval "${e.approvalId}" 已失效`);return this.emitApprovalResolved(r,"approve"===t.decision?{status:"resolved",decision:"approve"}:{status:"resolved",decision:"reject",...void 0!==t.reason?{reason:t.reason}:{}}),{resolved:!0}}getPendingApprovalExpiresAt(e){return this.findPendingApproval(e)?.expiresAt}async stageAttachment(e){return this.mutationRequests.run(e.requestId,o.attachmentStage,e,()=>{this.assertOpen(),this.requireThread(e.threadId);const t=this.requireAttachmentStore().stage({threadId:e.threadId,fileName:e.fileName,mediaType:e.mediaType,bytes:e.bytes,sha256:e.sha256,source:e.source,sourcePath:e.sourcePath});return t.ok||this.throwAttachmentFailure(t),{attachmentId:t.attachmentId,state:t.state,...void 0!==t.descriptor?{descriptor:t.descriptor}:{}}})}async appendAttachmentChunk(e){return this.mutationRequests.run(e.requestId,o.attachmentChunk,e,()=>{this.assertOpen();const t=this.requireAttachmentStore().appendChunk({threadId:e.threadId,attachmentId:e.attachmentId,sequence:e.sequence,dataBase64:e.dataBase64});return t.ok||this.throwAttachmentFailure(t),{receivedBytes:t.receivedBytes,nextSequence:t.nextSequence}})}async commitAttachment(e){return this.mutationRequests.run(e.requestId,o.attachmentCommit,e,()=>{this.assertOpen();const t=this.requireAttachmentStore().commit({threadId:e.threadId,attachmentId:e.attachmentId});return t.ok||this.throwAttachmentFailure(t),{descriptor:t.descriptor}})}async releaseAttachment(e){return this.mutationRequests.run(e.requestId,o.attachmentRelease,e,()=>{this.assertOpen();return{released:this.requireAttachmentStore().release({threadId:e.threadId,attachmentId:e.attachmentId}).released}})}requireAttachmentStore(){if(void 0===this.attachmentStore)throw new RuntimeServiceError(i.capabilityUnavailable,"Runtime 未配置附件存储,attachments 能力不可用");return this.attachmentStore}throwAttachmentFailure(e){throw new RuntimeServiceError(e.code,e.message,{...void 0!==e.retryable?{retryable:e.retryable}:{}})}resolveTurnAttachments(e){const t=e.input.attachments;if(void 0===t||0===t.length)return;const r=this.requireAttachmentStore(),s=new Set,n=[];for(const a of t){if(s.has(a))throw new RuntimeServiceError(i.invalidParams,`附件 "${a}" 在同一 Turn 中重复引用`);s.add(a);const t=r.readCommitted({threadId:e.threadId,attachmentId:a});t.ok||this.throwAttachmentFailure(t),n.push({data:t.dataBase64,mediaType:t.descriptor.mediaType})}return n}cancelPendingApproval(e,t){const r=this.findPendingApproval(e);return void 0!==r&&(this.pendingApprovals.delete(e.approvalId),this.emitApprovalResolved(r,t),!0)}async failPendingApprovalInteraction(e,t,r={status:"cancelled",reason:t}){const s=this.findPendingApproval(e);if(void 0===s)return!1;const n=this.activeTurns.get(e.threadId);void 0!==n&&n.turnId===e.turnId&&(n.interactionFailure=t),this.pendingApprovals.delete(e.approvalId);try{this.emitApprovalResolved(s,r)}finally{s.session.cancel()}return!0}resolvePendingUserInput(e,t){const r=this.pendingUserInputs.get(e);if(void 0===r)return!1;let s;try{s=v(r.form,t)}catch{return this.cancelPendingUserInput(e,"用户输入不符合原始表单约束"),!1}this.pendingUserInputs.delete(e);const n=r.session.resolveUserInput?.(e,s)??!1;if(!n){const t="用户输入请求已失效";return r.session.cancelUserInput?.(e,t),this.restoreRunningStatus(r),this.emitUserInputInteraction({type:"settled",requestId:e,threadId:r.threadId,turnId:r.turnId,reason:t}),!1}return this.restoreRunningStatus(r),this.emitUserInputInteraction({type:"settled",requestId:e,threadId:r.threadId,turnId:r.turnId,reason:"submitted"===s.status?"用户已提交输入":"用户已取消输入"}),n}cancelPendingUserInput(e,t){const r=this.pendingUserInputs.get(e);if(void 0===r)return!1;this.pendingUserInputs.delete(e);const s=r.session.cancelUserInput?.(e,t)??!1;return this.restoreRunningStatus(r),this.emitUserInputInteraction({type:"settled",requestId:e,threadId:r.threadId,turnId:r.turnId,reason:t}),s}getApprovalPreview(e){this.assertOpen();const t=this.requirePendingApproval(e);if(void 0===t.fullDiff||void 0!==t.expiresAt&&Date.parse(t.expiresAt)<=Date.now())throw new RuntimeServiceError(i.approvalNotFound,"完整预览不存在或审批已失效");const r=t.fullDiff.slice(e.offset,e.offset+e.maxChars),s=e.offset+r.length;return{text:r,totalChars:t.fullDiff.length,nextOffset:s<t.fullDiff.length?s:null}}getOperation(e){this.assertOpen(),this.requireThread(e.threadId);const t=this.store.getToolExecution(e.threadId,e.operationId);return{operation:void 0===t?null:Y(t,this.store.getAppOutputDescriptor(e.threadId,t.id))}}getOperationResult(e){this.assertOpen(),this.requireThread(e.threadId);const t=this.store.getToolExecution(e.threadId,e.operationId);if(void 0===t)return{result:null};const r=this.store.getAppOutput(e.threadId,e.operationId)??{status:"not_provided"};return{result:{threadId:e.threadId,operationId:e.operationId,agentName:t.agentName,toolName:t.toolName,createdAt:t.createdAt,output:r}}}async close(){if(this.closing)return;this.closing=!0,this.setUserInputAvailable(!1);for(const e of this.activeTurns.values())e.session.cancel();const e=[...this.sessions.values()];this.sessions.clear(),this.activeTurns.clear(),this.activeTurnOwners.clear(),this.settledTurnOwners.clear(),this.pendingApprovals.clear(),this.pendingUserInputs.clear(),this.userInputListeners.clear(),this.attachmentStore?.close(),await Promise.allSettled(e.map(e=>e.close())),this.mutationRequests.clear(),this.fatalErrorListeners.clear()}assertOpen(){if(this.closing)throw new RuntimeServiceError(i.runtimeClosing,"Runtime 正在关闭",{retryable:!0})}requireThread(e){const t=this.store.getThread(e);if(void 0===t)throw new RuntimeServiceError(i.threadNotFound,`Thread "${e}" 不存在`);return t}async requireSession(e){this.assertOpen(),this.requireThread(e);const t=this.sessions.get(e);if(void 0!==t)return t;const r=await this.engine.resumeSession(e);return this.rememberSession(r),r}rememberSession(e){e.setUserInputAvailable?.(this.userInputAvailable),this.sessions.set(e.id,e)}emit(e,t,r){const s=(new Date).toISOString(),n={protocolVersion:d,runtimeInstanceId:this.runtimeInstanceId,sequence:this.sequence,timestamp:s,threadId:e,...void 0!==t?{turnId:t}:{}},i=y.safeParse(r),a=i.success?(()=>{let r;try{r=this.store.appendRuntimeEvent({threadId:e,...void 0===t?{}:{turnId:t},timestamp:s,event:i.data})}catch(e){throw this.notifyFatalError(e),e}return{...n,durability:"durable",eventId:r.eventId,cursor:r.cursor,event:i.data}})():{...n,durability:"ephemeral",event:T.parse(r)};this.sequence+=1;for(const e of this.listeners)try{e(a)}catch{}}notifyFatalError(e){for(const e of this.activeTurns.values())try{e.session.cancel()}catch{}for(const t of this.fatalErrorListeners)try{t(e)}catch{}}async driveTurn(e,t,r){const s={streamId:void 0,text:"",terminalEvent:void 0},n=void 0!==r&&r.length>0?{text:t,attachments:r}:t;let i;try{for await(const t of e.session.send(n))this.projectSessionEvent(e,s,t);i=s.terminalEvent??{type:"turn.completed"}}catch(e){i=s.terminalEvent??{type:"turn.failed",stage:"execute",message:b(W(e))}}finally{this.activeTurns.get(e.threadId)===e&&this.activeTurns.delete(e.threadId),this.settleTurnOwner(e)}void 0!==s.streamId&&this.projectSessionEvent(e,s,{type:"message-finish",text:s.text}),this.emitTurnTerminal(e,i)}findTurnOwner(e,t){const r=this.activeTurnOwners.get(e);if(void 0!==r)return r;const s=this.settledTurnOwners.get(e);return s===t&&(this.settledTurnOwners.delete(e),this.settledTurnOwners.set(e,s)),s}settleTurnOwner(e){if(this.activeTurnOwners.get(e.turnId)===e.threadId&&(this.activeTurnOwners.delete(e.turnId),!this.closing))for(this.settledTurnOwners.set(e.turnId,e.threadId);this.settledTurnOwners.size>this.idempotencyCacheEntries;){const e=this.settledTurnOwners.keys().next().value;if(void 0===e)return;this.settledTurnOwners.delete(e)}}projectSessionEvent(e,r,s){switch(s.type){case"message-start":{if(void 0!==r.streamId)return;const s=q.parse(t());return r.streamId=s,r.text="",void this.emit(e.threadId,e.turnId,{type:"message.started",streamId:s})}case"text-delta":{const n=r.streamId??q.parse(t());return void 0===r.streamId&&(r.streamId=n,this.emit(e.threadId,e.turnId,{type:"message.started",streamId:n})),r.text+=s.delta,void this.emit(e.threadId,e.turnId,{type:"message.delta",streamId:n,delta:s.delta})}case"message-finish":{const n=r.streamId??q.parse(t());return void 0===r.streamId&&this.emit(e.threadId,e.turnId,{type:"message.started",streamId:n}),this.emit(e.threadId,e.turnId,{type:"message.completed",streamId:n,text:b(r.text||s.text)}),r.streamId=void 0,void(r.text="")}case"reasoning-delta":{const t=this.reasoningSummaryProjector?.(s.delta);return void(void 0!==t&&t.length>0&&this.emit(e.threadId,e.turnId,{type:"reasoning.summary.delta",reasoningId:s.reasoningId,delta:b(t)}))}case"tool-call":return void this.emit(e.threadId,e.turnId,{type:"tool.started",toolCallId:s.toolCallId,agentName:s.agentName,toolName:s.toolName,input:z(s.input,void 0)});case"tool-output-delta":return void this.emit(e.threadId,e.turnId,{type:"tool.output",toolCallId:s.toolCallId,agentName:s.agentName,toolName:s.toolName,stream:s.stream,delta:b(s.delta)});case"tool-result":return void this.emit(e.threadId,e.turnId,{type:"tool.completed",appOutput:void 0===s.executionId?{status:"not_provided"}:this.store.getAppOutputDescriptor(e.threadId,s.executionId)??{status:"not_provided"},toolCallId:s.toolCallId,agentName:s.agentName,toolName:s.toolName,...void 0!==s.executionId?{operationId:g.parse(s.executionId)}:{},...void 0!==s.outcome?{outcome:this.projectToolOutcome(s.outcome)}:{},display:z(s.display,void 0)});case"confirmation-required":{const t=Z(e.turnId,s);return this.pendingApprovals.set(t.id,{threadId:e.threadId,session:e.session,approval:t,expiresAt:s.expiresAt,fullDiff:void 0===s.fullDiff?void 0:b(s.fullDiff)}),void this.emit(e.threadId,e.turnId,{type:"approval.required",approval:t})}case"user-input-required":{if(!this.userInputAvailable||void 0===e.session.resolveUserInput||void 0===e.session.cancelUserInput)return void e.session.cancelUserInput?.(s.requestId,"当前客户端未协商用户输入处理能力");const t=x.parse(s.form),r=x.parse(t),n={requestId:s.requestId,threadId:e.threadId,turnId:e.turnId,session:e.session,form:t,expiresAt:s.expiresAt};this.pendingUserInputs.set(s.requestId,n),e.status="waiting-for-user";return void(this.emitUserInputInteraction({type:"required",requestId:s.requestId,threadId:e.threadId,turnId:e.turnId,form:r,expiresAt:s.expiresAt})||this.cancelPendingUserInput(s.requestId,"当前没有可处理用户输入请求的客户端"))}case"user-input-settled":{const e=this.pendingUserInputs.get(s.requestId);if(void 0===e)return;return this.pendingUserInputs.delete(s.requestId),this.restoreRunningStatus(e),void this.emitUserInputInteraction({type:"settled",requestId:e.requestId,threadId:e.threadId,turnId:e.turnId,reason:"submitted"===s.status?"用户输入请求已结算":"用户输入请求已取消"})}case"turn-cancelled":r.terminalEvent??=void 0===e.interactionFailure?{type:"turn.cancelled",reason:s.reason,message:b(s.message)}:{type:"turn.failed",stage:"execute",message:b(e.interactionFailure)};break;case"error":r.terminalEvent??={type:"turn.failed",stage:s.stage,message:b(s.message)};break;case"context-recovery":this.emit(e.threadId,e.turnId,{type:"context.recovery.changed",contextRecovery:s.state})}}projectToolOutcome(e){return{kind:e.kind,..."reason"in e&&void 0!==e.reason?{reason:b(e.reason)}:{}}}findPendingApproval(e){const t=this.pendingApprovals.get(e.approvalId);if(void 0!==t&&t.threadId===e.threadId&&t.approval.turnId===e.turnId)return t}requirePendingApproval(e){const t=this.findPendingApproval(e);if(void 0===t)throw new RuntimeServiceError(i.approvalNotFound,`Approval "${e.approvalId}" 不存在或已失效`);return t}emitApprovalResolved(e,t){const r="reason"in t&&void 0!==t.reason?{...t,reason:b(t.reason)}:t;this.emit(e.threadId,e.approval.turnId,{type:"approval.resolved",approvalId:e.approval.id,resolution:r})}cancelPendingApprovalsForTurn(e,t){const r=[...this.pendingApprovals.values()].filter(t=>t.approval.turnId===e);let s;for(const e of r)try{this.cancelPendingApproval({threadId:e.threadId,turnId:e.approval.turnId,approvalId:e.approval.id},t)}catch(e){s??=e}if(void 0!==s)throw s}cancelPendingUserInputsForTurn(e,t){const r=[...this.pendingUserInputs.values()].filter(t=>t.turnId===e).map(e=>e.requestId);for(const e of r)this.cancelPendingUserInput(e,t)}cancelAllPendingUserInputs(e){for(const t of[...this.pendingUserInputs.keys()])this.cancelPendingUserInput(t,e)}restoreRunningStatus(e){const t=this.activeTurns.get(e.threadId);void 0!==t&&t.turnId===e.turnId&&"waiting-for-user"===t.status&&(t.status="running")}emitUserInputInteraction(e){let t=!1;for(const r of this.userInputListeners)try{r(e),t=!0}catch{}return t}emitTurnTerminal(e,t){this.cancelPendingUserInputsForTurn(e.turnId,`Turn 已终止:${t.type}`),this.cancelPendingApprovalsForTurn(e.turnId,"turn.cancelled"===t.type&&"timeout"===t.reason?{status:"expired",reason:"Turn 已超时"}:{status:"cancelled",reason:`Turn 已终止:${t.type}`}),this.emit(e.threadId,e.turnId,t)}}
1
+ import{createHash as e,randomUUID as t}from"node:crypto";import{APPROVAL_DIFF_PREVIEW_KEY as r,initializeResultSchema as s,APPROVAL_EXPLANATION_PREVIEW_KEY as n,RUNTIME_ERROR_CODES as i,RUNTIME_FEATURES_V13 as a,RUNTIME_METHODS as o,RUNTIME_PROTOCOL_VERSION as d,RUNTIME_V14_MAX_ATTACHMENT_BYTES as u,RUNTIME_V14_MAX_ATTACHMENT_CHUNK_BYTES as h,RUNTIME_V14_MAX_STAGED_ATTACHMENTS as c,RUNTIME_V14_MAX_TURN_ATTACHMENTS as l,SUPPORTED_RUNTIME_PROTOCOL_VERSIONS as p,approvalExplanationSchema as m,approvalIdSchema as v,normalizeUserInputResultForForm as I,operationIdSchema as g,parseLatestRuntimeMethodResult as f,runtimeDurableEventV16Schema as y,runtimeEphemeralEventV16Schema as T,runtimeInstanceIdSchema as A,runtimeProtocolVersionSchema as w,streamIdSchema as S,threadIdSchema as q,userInputFormSchema as x}from"@roll-agent/protocol";import{AttachmentStore as R}from"./attachment-store.js";import{createSafeCapabilitySnapshot as b}from"../engine/capability-manifest.js";import{TurnReasoningDisplay as E}from"./turn-reasoning-display.js";import{isSensitiveFieldName as O,redactSecretText as P,toRedactedToolExecutionRecordSummary as C}from"../tool-bridge/tool-execution-record.js";import{RuntimeEventCursorExpiredError as U,RuntimeEventCursorGapError as N,ThreadStore as F}from"../store/thread-store.js";const k=4194304,j=500,B=1e4,M=16e3,D=64,V=128,$=16,L=new Set(["_meta","authorization","cookie","password","provideroptions","raw","secret","token"]);export class RuntimeServiceError extends Error{rollCode;retryable;details;constructor(e,t,r={}){super(t),this.name="RuntimeServiceError",this.rollCode=e,this.retryable=r.retryable??!1,this.details=r.details}}function _(t){const r=JSON.stringify(t);if(void 0===r)throw new RuntimeServiceError(i.invalidParams,"无法为 mutation 请求生成稳定指纹");return e("sha256").update(r).digest("hex")}export class MutationRequestCache{maxEntries;inFlight=new Map;settled=new Map;constructor(e){if(!Number.isInteger(e)||e<1)throw new Error("idempotencyCacheEntries must be a positive integer");this.maxEntries=e}run(e,t,r,s){const n=_(r),i=this.inFlight.get(e);if(void 0!==i)return this.assertMatchingRequest(e,t,n,i),i.response.then(e=>f(t,e));const a=this.settled.get(e);if(void 0!==a)return this.assertMatchingRequest(e,t,n,a),this.settled.delete(e),this.settled.set(e,a),a.response.then(e=>f(t,e));const o=Promise.resolve().then(s),d={method:t,fingerprint:n,response:o};return this.inFlight.set(e,d),o.then(()=>{this.settle(e,d)},()=>{this.settle(e,d)}),o}clear(){this.inFlight.clear(),this.settled.clear()}assertMatchingRequest(e,t,r,s){if(s.method!==t||s.fingerprint!==r)throw new RuntimeServiceError(i.invalidParams,`requestId "${e}" 已用于不同请求`)}settle(e,t){if(this.inFlight.get(e)===t)for(this.inFlight.delete(e),this.settled.set(e,t);this.settled.size>this.maxEntries;){const e=this.settled.keys().next().value;if(void 0===e)return;this.settled.delete(e)}}}function z(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function W(e,t,r=0){if(void 0!==t&&(L.has(t.toLowerCase())||O(t)))return"[redacted]";if(r>=$)return"[nested value omitted]";if(null===e||"boolean"==typeof e)return e;if("string"==typeof e){const t=P(e);return t.length<=M?t:`${t.slice(0,M)}\n[value clipped]`}if("number"==typeof e)return Number.isFinite(e)?e:String(e);if(Array.isArray(e)){const t=e.slice(0,D).map(e=>W(e,void 0,r+1));return e.length>D&&t.push(`[${String(e.length-D)} items omitted]`),t}if(z(e)){const t={};for(const[s,n]of Object.entries(e).slice(0,V))void 0!==n&&(t[s]=W(n,s,r+1));return Object.keys(e).length>V&&(t._omitted=`${String(Object.keys(e).length-V)} keys omitted`),t}return void 0===e?null:String(e)}function G(e){return e instanceof Error?e.message:String(e)}function J(e){const t=e.content;return"string"==typeof t?t:Array.isArray(t)?t.flatMap(e=>z(e)&&"text"===e.type&&"string"==typeof e.text?[e.text]:[]).join(""):""}function H(e){const t=e.endsWith("==")?2:e.endsWith("=")?1:0;return Math.max(0,3*Math.floor(e.length/4)-t)}function K(e){const t=e.content;return"user"===e.role&&Array.isArray(t)?t.flatMap(e=>z(e)?"file"===e.type&&"string"==typeof e.mediaType&&"string"==typeof e.data?[{type:"attachment",mediaType:e.mediaType,bytes:H(e.data)}]:"image"===e.type&&"string"==typeof e.image?[{type:"attachment",mediaType:"image/*",bytes:H(e.image)}]:[]:[]):[]}function Q(e){return q.parse(e)}function X(e,t){return{id:Q(t.id),...void 0!==t.title?{title:t.title}:{},...void 0!==t.model?{model:t.model}:{},createdAt:t.createdAt,updatedAt:t.updatedAt,messageCount:e.countTranscriptMessages(t.id)}}function Y(e){if("user"!==e.message.role&&"assistant"!==e.message.role)return;const t=P(J(e.message));return{sequence:e.sequence,role:e.message.role,createdAt:e.createdAt,parts:[...t.length>0?[{type:"text",text:t}]:[],...K(e.message)]}}function Z(e,t={status:"not_provided"}){const r=C(e);return{id:g.parse(r.id),sequence:e.sequence,toolCallId:r.toolCallId,agentName:r.agentName,toolName:r.toolName,createdAt:r.createdAt,outcome:{kind:r.outcome.kind,..."reason"in r.outcome&&void 0!==r.outcome.reason?{reason:r.outcome.reason}:{}},display:W(r.display,void 0),appOutput:t}}function ee(e,t){const s=W(t.input,void 0),i=void 0===t.explanation?void 0:m.safeParse(P(t.explanation)),a=void 0===t.diff?void 0:W(t.diff,void 0),o=z(s)?{...s,...!0===i?.success?{[n]:i.data}:{},...void 0!==a?{[r]:a}:{},...void 0!==t.fullDiff?{fullDiffAvailable:!0}:{}}:s;return{id:v.parse(t.approvalId),turnId:e,agentName:t.agentName,toolName:t.toolName,preview:o,...void 0!==t.reason?{reason:P(t.reason)}:{}}}export class RuntimeService{runtimeInstanceId;engine;store;serverName;serverVersion;runtimeVersion;maxFrameBytes;idempotencyCacheEntries;reasoningSummaryProjector;providerReasoning;reasoningTextSubscription;attachmentStore;sessions=new Map;activeTurns=new Map;activeTurnOwners=new Map;settledTurnOwners=new Map;pendingApprovals=new Map;pendingUserInputs=new Map;listeners=new Set;fatalErrorListeners=new Set;userInputListeners=new Set;mutationRequests;sequence=0;closing=!1;userInputAvailable=!1;constructor(e,r,s={}){this.engine=e,this.store=r,this.serverName=s.serverName??"roll-runtime",this.serverVersion=s.serverVersion??"1.0",this.runtimeVersion=s.runtimeVersion??"development",this.maxFrameBytes=s.maxFrameBytes??k,this.idempotencyCacheEntries=s.idempotencyCacheEntries??B,this.mutationRequests=new MutationRequestCache(this.idempotencyCacheEntries),this.reasoningSummaryProjector=s.reasoningSummaryProjector,this.providerReasoning=s.providerReasoning,this.attachmentStore=s.attachmentStore,this.runtimeInstanceId=A.parse(t())}initialize(e){let t;this.assertOpen();for(const r of e.protocolVersions){const e=w.safeParse(r);if(e.success){t=e.data;break}}if(void 0===t)throw new RuntimeServiceError(i.protocolVersionUnsupported,`不支持客户端协议版本:${e.protocolVersions.join(", ")}`,{details:{supportedVersions:p}});const r=a.filter(e=>"reasoning-summary"!==e||"summary"===this.providerReasoning||void 0===this.providerReasoning&&void 0!==this.reasoningSummaryProjector),n={protocolVersion:t,runtimeInstanceId:this.runtimeInstanceId,server:{name:this.serverName,version:this.serverVersion,runtimeVersion:this.runtimeVersion},features:r,limits:{maxFrameBytes:this.maxFrameBytes,maxPageSize:j,idempotencyCacheEntries:this.idempotencyCacheEntries}};if("1.4"===t||"1.5"===t||"1.6"===t){const e=this.attachmentStore?.limits;return s.parse({...n,protocolVersion:t,features:[...r,...void 0!==this.attachmentStore?["attachments"]:[],..."1.5"===t||"1.6"===t?["app-output"]:[]],limits:{...n.limits,eventReplay:!0,maxAttachmentBytes:e?.maxAttachmentBytes??u,maxAttachmentChunkBytes:e?.maxAttachmentChunkBytes??h,maxTurnAttachments:l,maxStagedAttachments:e?.maxStagedAttachments??c}})}return"1.3"===t?{...n,protocolVersion:t,limits:{...n.limits,eventReplay:!0}}:{...n,protocolVersion:t,limits:{...n.limits,eventReplay:!1}}}subscribeReasoningText(e){if(this.assertOpen(),"text"!==this.providerReasoning||this.reasoningTextSubscription)return;const t={deliver:e};return this.reasoningTextSubscription=t,()=>{this.reasoningTextSubscription===t&&(this.reasoningTextSubscription=void 0)}}onEvent(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}onFatalError(e){return this.fatalErrorListeners.add(e),()=>{this.fatalErrorListeners.delete(e)}}onUserInputInteraction(e){return this.userInputListeners.add(e),()=>{this.userInputListeners.delete(e)}}setUserInputAvailable(e){if(this.userInputAvailable!==e){this.userInputAvailable=e,e||this.cancelAllPendingUserInputs("当前客户端已撤销用户输入处理能力");for(const t of this.sessions.values())t.setUserInputAvailable?.(e)}}listThreads(e){this.assertOpen();const t=void 0===e.cursor?0:Number(e.cursor);if(!Number.isSafeInteger(t)||t<0)throw new RuntimeServiceError(i.invalidParams,"thread.list cursor 超出安全整数范围");const r=this.store.listThreads({origin:"interactive"}),s=r.slice(t,t+e.limit).map(e=>X(this.store,e)),n=t+s.length;return{items:s,nextCursor:n<r.length?String(n):null}}async createThread(e){return this.mutationRequests.run(e.requestId,o.threadCreate,e,async()=>{this.assertOpen();const t=await this.engine.createSession(void 0!==e.title?{title:e.title}:{});return this.rememberSession(t),{thread:X(this.store,this.requireThread(t.id))}})}async openThread(e){return this.assertOpen(),"scheduled"!==this.requireThread(e.threadId).origin.kind&&await this.requireSession(e.threadId),this.snapshotThread({threadId:e.threadId,limit:100})}snapshotThread(e){this.assertOpen();const t=this.requireThread(e.threadId),r=this.store.listRecentTranscriptMessages(e.threadId,{...void 0!==e.messageBeforeSequence?{beforeSequence:e.messageBeforeSequence}:{},limit:e.limit}),s=this.store.listRecentToolExecutions(e.threadId,{...void 0!==e.operationBeforeSequence?{beforeSequence:e.operationBeforeSequence}:{},limit:e.limit}),n=this.activeTurns.get(e.threadId),i=void 0===n?void 0:{id:n.turnId,status:n.status,startedAt:n.startedAt};return{thread:X(this.store,t),messages:{items:r.entries.flatMap(e=>{const t=Y(e);return void 0===t?[]:[t]}),nextBeforeSequence:r.nextBeforeSequence??null},operations:{items:s.entries.map(t=>Z(t,this.store.getAppOutputDescriptor(e.threadId,t.id))),nextBeforeSequence:s.nextBeforeSequence??null},...void 0!==i?{activeTurn:i}:{},pendingApprovals:[...this.pendingApprovals.values()].filter(t=>t.threadId===e.threadId).map(e=>e.approval),transcriptCompleteness:this.store.getTranscriptCompleteness(e.threadId),eventCursor:this.store.getRuntimeEventCursor(e.threadId),contextRecovery:null}}resumeEvents(e){this.assertOpen(),this.requireThread(e.threadId);try{return this.store.resumeRuntimeEvents(e.threadId,e.afterCursor)}catch(t){if(t instanceof U)throw new RuntimeServiceError(i.eventCursorExpired,"Runtime Event cursor 已超出当前 Thread 的保留窗口,请回退到 thread.snapshot",{details:{threadId:e.threadId}});if(t instanceof N)throw new RuntimeServiceError(i.eventCursorGap,"Runtime Event cursor 与当前 Thread 事件日志不连续,请回退到 thread.snapshot",{details:{threadId:e.threadId}});throw t}}async renameThread(e){return this.mutationRequests.run(e.requestId,o.threadRename,e,()=>(this.assertOpen(),this.requireThread(e.threadId),this.store.updateTitle(e.threadId,e.title),{thread:X(this.store,this.requireThread(e.threadId))}))}async deleteThread(e){return this.mutationRequests.run(e.requestId,o.threadDelete,e,async()=>{if(this.assertOpen(),this.requireThread(e.threadId),this.activeTurns.has(e.threadId))throw new RuntimeServiceError(i.threadBusy,`Thread "${e.threadId}" 仍有活动 Turn`,{retryable:!0});const t=this.sessions.get(e.threadId);return void 0!==t&&(await t.close(),this.sessions.delete(e.threadId)),this.attachmentStore?.releaseThread(e.threadId),this.store.deleteThread(e.threadId),{deleted:!0}})}async detachThread(e){return this.mutationRequests.run(e.requestId,o.threadDetach,e,async()=>{if(this.assertOpen(),this.requireThread(e.threadId),this.activeTurns.has(e.threadId))return{detached:!1};const t=this.sessions.get(e.threadId);return void 0===t?{detached:!1}:(await t.close(),this.sessions.delete(e.threadId),{detached:!0})})}async threadCapabilities(e){const t=await this.requireSession(e.threadId);return{manifest:W(b(t.getCapabilityManifest(),t.getCapabilityTurnContext()),void 0)}}async startTurn(e){return this.mutationRequests.run(e.requestId,o.turnStart,e,async()=>{if(this.assertOpen(),"scheduled"===this.requireThread(e.threadId).origin.kind)throw new RuntimeServiceError(i.invalidParams,"定时执行会话是只读记录;请基于该次运行创建新对话");const t=this.findTurnOwner(e.turnId,e.threadId);if(void 0!==t){if(t===e.threadId)return{accepted:!0,turnId:e.turnId};throw new RuntimeServiceError(i.turnAlreadyActive,`Turn "${e.turnId}" 已属于另一个 Thread`)}if(this.activeTurns.has(e.threadId))throw new RuntimeServiceError(i.turnAlreadyActive,`Thread "${e.threadId}" 已有活动 Turn`,{retryable:!0});const r=await this.requireSession(e.threadId),s=this.findTurnOwner(e.turnId,e.threadId);if(void 0!==s){if(s===e.threadId)return{accepted:!0,turnId:e.turnId};throw new RuntimeServiceError(i.turnAlreadyActive,`Turn "${e.turnId}" 已属于另一个 Thread`)}if(this.activeTurns.has(e.threadId))throw new RuntimeServiceError(i.turnAlreadyActive,`Thread "${e.threadId}" 已有活动 Turn`,{retryable:!0});const n=this.resolveTurnAttachments(e),a={threadId:e.threadId,turnId:e.turnId,session:r,startedAt:(new Date).toISOString(),status:"running",interactionFailure:void 0},o=this.createTurnReasoningDisplay(a);this.activeTurns.set(e.threadId,a),this.activeTurnOwners.set(e.turnId,e.threadId);try{this.emit(e.threadId,e.turnId,{type:"turn.started"})}catch(t){throw this.activeTurns.delete(e.threadId),this.activeTurnOwners.delete(e.turnId),t}return this.driveTurn(a,e.input.text,n,o).catch(()=>{}),{accepted:!0,turnId:e.turnId}})}async cancelTurn(e){return this.mutationRequests.run(e.requestId,o.turnCancel,e,()=>{this.assertOpen();const t=this.activeTurns.get(e.threadId);if(void 0===t||t.turnId!==e.turnId)throw new RuntimeServiceError(i.turnNotFound,`Turn "${e.turnId}" 不存在或已结束`);t.status="cancelling";let r=!1;try{this.cancelPendingUserInputsForTurn(e.turnId,"Turn 已由客户端取消"),this.cancelPendingApprovalsForTurn(e.turnId,{status:"cancelled",reason:"Turn 已由客户端取消"})}finally{r=t.session.cancel()}return{cancelling:r}})}async respondApproval(e){return this.mutationRequests.run(e.requestId,o.approvalRespond,e,()=>this.resolvePendingApproval(e,"approve"===e.decision?{decision:"approve"}:{decision:"reject",...void 0!==e.reason?{reason:e.reason}:{}}))}resolvePendingApproval(e,t){this.assertOpen();const r=this.requirePendingApproval(e),s="approve"===t.decision?r.session.approve(e.approvalId,t.scope):r.session.reject(e.approvalId,t.reason);if(this.pendingApprovals.delete(e.approvalId),!s)throw this.emitApprovalResolved(r,{status:"cancelled",reason:"审批已失效"}),new RuntimeServiceError(i.approvalNotFound,`Approval "${e.approvalId}" 已失效`);return this.emitApprovalResolved(r,"approve"===t.decision?{status:"resolved",decision:"approve"}:{status:"resolved",decision:"reject",...void 0!==t.reason?{reason:t.reason}:{}}),{resolved:!0}}getPendingApprovalExpiresAt(e){return this.findPendingApproval(e)?.expiresAt}async stageAttachment(e){return this.mutationRequests.run(e.requestId,o.attachmentStage,e,()=>{this.assertOpen(),this.requireThread(e.threadId);const t=this.requireAttachmentStore().stage({threadId:e.threadId,fileName:e.fileName,mediaType:e.mediaType,bytes:e.bytes,sha256:e.sha256,source:e.source,sourcePath:e.sourcePath});return t.ok||this.throwAttachmentFailure(t),{attachmentId:t.attachmentId,state:t.state,...void 0!==t.descriptor?{descriptor:t.descriptor}:{}}})}async appendAttachmentChunk(e){return this.mutationRequests.run(e.requestId,o.attachmentChunk,e,()=>{this.assertOpen();const t=this.requireAttachmentStore().appendChunk({threadId:e.threadId,attachmentId:e.attachmentId,sequence:e.sequence,dataBase64:e.dataBase64});return t.ok||this.throwAttachmentFailure(t),{receivedBytes:t.receivedBytes,nextSequence:t.nextSequence}})}async commitAttachment(e){return this.mutationRequests.run(e.requestId,o.attachmentCommit,e,()=>{this.assertOpen();const t=this.requireAttachmentStore().commit({threadId:e.threadId,attachmentId:e.attachmentId});return t.ok||this.throwAttachmentFailure(t),{descriptor:t.descriptor}})}async releaseAttachment(e){return this.mutationRequests.run(e.requestId,o.attachmentRelease,e,()=>{this.assertOpen();return{released:this.requireAttachmentStore().release({threadId:e.threadId,attachmentId:e.attachmentId}).released}})}requireAttachmentStore(){if(void 0===this.attachmentStore)throw new RuntimeServiceError(i.capabilityUnavailable,"Runtime 未配置附件存储,attachments 能力不可用");return this.attachmentStore}throwAttachmentFailure(e){throw new RuntimeServiceError(e.code,e.message,{...void 0!==e.retryable?{retryable:e.retryable}:{}})}resolveTurnAttachments(e){const t=e.input.attachments;if(void 0===t||0===t.length)return;const r=this.requireAttachmentStore(),s=new Set,n=[];for(const a of t){if(s.has(a))throw new RuntimeServiceError(i.invalidParams,`附件 "${a}" 在同一 Turn 中重复引用`);s.add(a);const t=r.readCommitted({threadId:e.threadId,attachmentId:a});t.ok||this.throwAttachmentFailure(t),n.push({data:t.dataBase64,mediaType:t.descriptor.mediaType})}return n}cancelPendingApproval(e,t){const r=this.findPendingApproval(e);return void 0!==r&&(this.pendingApprovals.delete(e.approvalId),this.emitApprovalResolved(r,t),!0)}async failPendingApprovalInteraction(e,t,r={status:"cancelled",reason:t}){const s=this.findPendingApproval(e);if(void 0===s)return!1;const n=this.activeTurns.get(e.threadId);void 0!==n&&n.turnId===e.turnId&&(n.interactionFailure=t),this.pendingApprovals.delete(e.approvalId);try{this.emitApprovalResolved(s,r)}finally{s.session.cancel()}return!0}resolvePendingUserInput(e,t){const r=this.pendingUserInputs.get(e);if(void 0===r)return!1;let s;try{s=I(r.form,t)}catch{return this.cancelPendingUserInput(e,"用户输入不符合原始表单约束"),!1}this.pendingUserInputs.delete(e);const n=r.session.resolveUserInput?.(e,s)??!1;if(!n){const t="用户输入请求已失效";return r.session.cancelUserInput?.(e,t),this.restoreRunningStatus(r),this.emitUserInputInteraction({type:"settled",requestId:e,threadId:r.threadId,turnId:r.turnId,reason:t}),!1}return this.restoreRunningStatus(r),this.emitUserInputInteraction({type:"settled",requestId:e,threadId:r.threadId,turnId:r.turnId,reason:"submitted"===s.status?"用户已提交输入":"用户已取消输入"}),n}cancelPendingUserInput(e,t){const r=this.pendingUserInputs.get(e);if(void 0===r)return!1;this.pendingUserInputs.delete(e);const s=r.session.cancelUserInput?.(e,t)??!1;return this.restoreRunningStatus(r),this.emitUserInputInteraction({type:"settled",requestId:e,threadId:r.threadId,turnId:r.turnId,reason:t}),s}getApprovalPreview(e){this.assertOpen();const t=this.requirePendingApproval(e);if(void 0===t.fullDiff||void 0!==t.expiresAt&&Date.parse(t.expiresAt)<=Date.now())throw new RuntimeServiceError(i.approvalNotFound,"完整预览不存在或审批已失效");const r=t.fullDiff.slice(e.offset,e.offset+e.maxChars),s=e.offset+r.length;return{text:r,totalChars:t.fullDiff.length,nextOffset:s<t.fullDiff.length?s:null}}getOperation(e){this.assertOpen(),this.requireThread(e.threadId);const t=this.store.getToolExecution(e.threadId,e.operationId);return{operation:void 0===t?null:Z(t,this.store.getAppOutputDescriptor(e.threadId,t.id))}}getOperationResult(e){this.assertOpen(),this.requireThread(e.threadId);const t=this.store.getToolExecution(e.threadId,e.operationId);if(void 0===t)return{result:null};const r=this.store.getAppOutput(e.threadId,e.operationId)??{status:"not_provided"};return{result:{threadId:e.threadId,operationId:e.operationId,agentName:t.agentName,toolName:t.toolName,createdAt:t.createdAt,output:r}}}async close(){if(this.closing)return;this.closing=!0,this.setUserInputAvailable(!1);for(const e of this.activeTurns.values())e.session.cancel();const e=[...this.sessions.values()];this.sessions.clear(),this.activeTurns.clear(),this.activeTurnOwners.clear(),this.settledTurnOwners.clear(),this.pendingApprovals.clear(),this.pendingUserInputs.clear(),this.userInputListeners.clear(),this.reasoningTextSubscription=void 0,this.attachmentStore?.close(),await Promise.allSettled(e.map(e=>e.close())),this.mutationRequests.clear(),this.fatalErrorListeners.clear()}assertOpen(){if(this.closing)throw new RuntimeServiceError(i.runtimeClosing,"Runtime 正在关闭",{retryable:!0})}requireThread(e){const t=this.store.getThread(e);if(void 0===t)throw new RuntimeServiceError(i.threadNotFound,`Thread "${e}" 不存在`);return t}async requireSession(e){this.assertOpen(),this.requireThread(e);const t=this.sessions.get(e);if(void 0!==t)return t;const r=await this.engine.resumeSession(e);return this.rememberSession(r),r}rememberSession(e){e.setUserInputAvailable?.(this.userInputAvailable),this.sessions.set(e.id,e)}emit(e,t,r){const s=(new Date).toISOString(),n={protocolVersion:d,runtimeInstanceId:this.runtimeInstanceId,sequence:this.sequence,timestamp:s,threadId:e,...void 0!==t?{turnId:t}:{}},i=y.safeParse(r),a=i.success?(()=>{let r;try{r=this.store.appendRuntimeEvent({threadId:e,...void 0===t?{}:{turnId:t},timestamp:s,event:i.data})}catch(e){throw this.notifyFatalError(e),e}return{...n,durability:"durable",eventId:r.eventId,cursor:r.cursor,event:i.data}})():{...n,durability:"ephemeral",event:T.parse(r)};this.sequence+=1;const o="reasoning.text.delta"===r.type?this.reasoningTextSubscription?[this.reasoningTextSubscription.deliver]:[]:this.listeners;for(const e of o)try{e(a)}catch{}}notifyFatalError(e){for(const e of this.activeTurns.values())try{e.session.cancel()}catch{}for(const t of this.fatalErrorListeners)try{t(e)}catch{}}createTurnReasoningDisplay(e){const t=this.providerReasoning,r=this.reasoningSummaryProjector;if(void 0===t&&!r)return;const s=this.reasoningTextSubscription;if("text"===t&&!s)return;const n="text"===t?"reasoning.text.delta":"reasoning.summary.delta",i=()=>"text"!==t||s===this.reasoningTextSubscription;return new E(e=>{if(i())return void 0===t?r?.(e.delta):e.presentation===t?e.delta:void 0},(t,r)=>{i()&&this.emit(e.threadId,e.turnId,{type:n,reasoningId:t,delta:r})},void 0===t)}async driveTurn(e,t,r,s){const n={reasoning:s,streamId:void 0,text:"",terminalEvent:void 0},i=void 0!==r&&r.length>0?{text:t,attachments:r}:t;let a;try{for await(const t of e.session.send(i))this.projectSessionEvent(e,n,t);a=n.terminalEvent??{type:"turn.completed"}}catch(e){n.reasoning?.reset(),a=n.terminalEvent??{type:"turn.failed",stage:"execute",message:P(G(e))}}finally{this.activeTurns.get(e.threadId)===e&&this.activeTurns.delete(e.threadId),this.settleTurnOwner(e)}void 0!==n.streamId&&this.projectSessionEvent(e,n,{type:"message-finish",text:n.text}),this.emitTurnTerminal(e,a)}findTurnOwner(e,t){const r=this.activeTurnOwners.get(e);if(void 0!==r)return r;const s=this.settledTurnOwners.get(e);return s===t&&(this.settledTurnOwners.delete(e),this.settledTurnOwners.set(e,s)),s}settleTurnOwner(e){if(this.activeTurnOwners.get(e.turnId)===e.threadId&&(this.activeTurnOwners.delete(e.turnId),!this.closing))for(this.settledTurnOwners.set(e.turnId,e.threadId);this.settledTurnOwners.size>this.idempotencyCacheEntries;){const e=this.settledTurnOwners.keys().next().value;if(void 0===e)return;this.settledTurnOwners.delete(e)}}projectSessionEvent(e,r,s){switch(s.type){case"message-start":{if(r.reasoning?.reset(),void 0!==r.streamId)return;const s=S.parse(t());return r.streamId=s,r.text="",void this.emit(e.threadId,e.turnId,{type:"message.started",streamId:s})}case"text-delta":{const n=r.streamId??S.parse(t());return void 0===r.streamId&&(r.streamId=n,this.emit(e.threadId,e.turnId,{type:"message.started",streamId:n})),r.text+=s.delta,void this.emit(e.threadId,e.turnId,{type:"message.delta",streamId:n,delta:s.delta})}case"message-finish":{r.reasoning?.finish();const n=r.streamId??S.parse(t());return void 0===r.streamId&&this.emit(e.threadId,e.turnId,{type:"message.started",streamId:n}),this.emit(e.threadId,e.turnId,{type:"message.completed",streamId:n,text:P(r.text||s.text)}),r.streamId=void 0,void(r.text="")}case"reasoning-start":return void r.reasoning?.start(s.reasoningId);case"reasoning-delta":return void r.reasoning?.append(s);case"reasoning-end":return void r.reasoning?.end(s.reasoningId);case"tool-call":return void this.emit(e.threadId,e.turnId,{type:"tool.started",toolCallId:s.toolCallId,agentName:s.agentName,toolName:s.toolName,input:W(s.input,void 0)});case"tool-output-delta":return void this.emit(e.threadId,e.turnId,{type:"tool.output",toolCallId:s.toolCallId,agentName:s.agentName,toolName:s.toolName,stream:s.stream,delta:P(s.delta)});case"tool-result":return void this.emit(e.threadId,e.turnId,{type:"tool.completed",appOutput:void 0===s.executionId?{status:"not_provided"}:this.store.getAppOutputDescriptor(e.threadId,s.executionId)??{status:"not_provided"},toolCallId:s.toolCallId,agentName:s.agentName,toolName:s.toolName,...void 0!==s.executionId?{operationId:g.parse(s.executionId)}:{},...void 0!==s.outcome?{outcome:this.projectToolOutcome(s.outcome)}:{},display:W(s.display,void 0)});case"confirmation-required":{const t=ee(e.turnId,s);return this.pendingApprovals.set(t.id,{threadId:e.threadId,session:e.session,approval:t,expiresAt:s.expiresAt,fullDiff:void 0===s.fullDiff?void 0:P(s.fullDiff)}),void this.emit(e.threadId,e.turnId,{type:"approval.required",approval:t})}case"user-input-required":{if(!this.userInputAvailable||void 0===e.session.resolveUserInput||void 0===e.session.cancelUserInput)return void e.session.cancelUserInput?.(s.requestId,"当前客户端未协商用户输入处理能力");const t=x.parse(s.form),r=x.parse(t),n={requestId:s.requestId,threadId:e.threadId,turnId:e.turnId,session:e.session,form:t,expiresAt:s.expiresAt};this.pendingUserInputs.set(s.requestId,n),e.status="waiting-for-user";return void(this.emitUserInputInteraction({type:"required",requestId:s.requestId,threadId:e.threadId,turnId:e.turnId,form:r,expiresAt:s.expiresAt})||this.cancelPendingUserInput(s.requestId,"当前没有可处理用户输入请求的客户端"))}case"user-input-settled":{const e=this.pendingUserInputs.get(s.requestId);if(void 0===e)return;return this.pendingUserInputs.delete(s.requestId),this.restoreRunningStatus(e),void this.emitUserInputInteraction({type:"settled",requestId:e.requestId,threadId:e.threadId,turnId:e.turnId,reason:"submitted"===s.status?"用户输入请求已结算":"用户输入请求已取消"})}case"turn-cancelled":r.reasoning?.reset(),r.terminalEvent??=void 0===e.interactionFailure?{type:"turn.cancelled",reason:s.reason,message:P(s.message)}:{type:"turn.failed",stage:"execute",message:P(e.interactionFailure)};break;case"error":r.reasoning?.reset(),r.terminalEvent??={type:"turn.failed",stage:s.stage,message:P(s.message)};break;case"context-recovery":this.emit(e.threadId,e.turnId,{type:"context.recovery.changed",contextRecovery:s.state});break;case"model-step-start":case"model-recovery":r.reasoning?.reset();break;case"step-finish":r.reasoning?.finish()}}projectToolOutcome(e){return{kind:e.kind,..."reason"in e&&void 0!==e.reason?{reason:P(e.reason)}:{}}}findPendingApproval(e){const t=this.pendingApprovals.get(e.approvalId);if(void 0!==t&&t.threadId===e.threadId&&t.approval.turnId===e.turnId)return t}requirePendingApproval(e){const t=this.findPendingApproval(e);if(void 0===t)throw new RuntimeServiceError(i.approvalNotFound,`Approval "${e.approvalId}" 不存在或已失效`);return t}emitApprovalResolved(e,t){const r="reason"in t&&void 0!==t.reason?{...t,reason:P(t.reason)}:t;this.emit(e.threadId,e.approval.turnId,{type:"approval.resolved",approvalId:e.approval.id,resolution:r})}cancelPendingApprovalsForTurn(e,t){const r=[...this.pendingApprovals.values()].filter(t=>t.approval.turnId===e);let s;for(const e of r)try{this.cancelPendingApproval({threadId:e.threadId,turnId:e.approval.turnId,approvalId:e.approval.id},t)}catch(e){s??=e}if(void 0!==s)throw s}cancelPendingUserInputsForTurn(e,t){const r=[...this.pendingUserInputs.values()].filter(t=>t.turnId===e).map(e=>e.requestId);for(const e of r)this.cancelPendingUserInput(e,t)}cancelAllPendingUserInputs(e){for(const t of[...this.pendingUserInputs.keys()])this.cancelPendingUserInput(t,e)}restoreRunningStatus(e){const t=this.activeTurns.get(e.threadId);void 0!==t&&t.turnId===e.turnId&&"waiting-for-user"===t.status&&(t.status="running")}emitUserInputInteraction(e){let t=!1;for(const r of this.userInputListeners)try{r(e),t=!0}catch{}return t}emitTurnTerminal(e,t){this.cancelPendingUserInputsForTurn(e.turnId,`Turn 已终止:${t.type}`),this.cancelPendingApprovalsForTurn(e.turnId,"turn.cancelled"===t.type&&"timeout"===t.reason?{status:"expired",reason:"Turn 已超时"}:{status:"cancelled",reason:`Turn 已终止:${t.type}`}),this.emit(e.threadId,e.turnId,t)}}
@@ -0,0 +1,20 @@
1
+ import type { SessionEvent } from "../types/events.ts";
2
+ type Delta = Extract<SessionEvent, {
3
+ type: "reasoning-delta";
4
+ }>;
5
+ /** Per-turn display state. Native block IDs can repeat between SDK steps or retries. */
6
+ export declare class TurnReasoningDisplay {
7
+ private readonly blocks;
8
+ private overflowed;
9
+ private nextId;
10
+ private readonly readDelta;
11
+ private readonly publish;
12
+ private readonly preserveNativeId;
13
+ constructor(readDelta: (event: Delta) => string | undefined, publish: (id: string, delta: string) => void, preserveNativeId?: boolean);
14
+ start(nativeId: string): void;
15
+ append(event: Delta): void;
16
+ end(nativeId: string): void;
17
+ finish(): void;
18
+ reset(): void;
19
+ }
20
+ export {};
@@ -0,0 +1 @@
1
+ import{ReasoningDisplayBuffer as e}from"./reasoning-display-buffer.js";const s=16;export class TurnReasoningDisplay{blocks=new Map;overflowed=!1;nextId=0;readDelta;publish;preserveNativeId;constructor(e,s,t=!1){this.readDelta=e,this.publish=s,this.preserveNativeId=t}start(e){this.blocks.delete(e)}append(t){if(this.overflowed)return;const i=this.readDelta(t);if(!i)return;let r=this.blocks.get(t.reasoningId);if(!r){if(this.blocks.size>=s)return this.blocks.clear(),void(this.overflowed=!0);r={id:this.preserveNativeId&&t.reasoningId?t.reasoningId:String(++this.nextId),buffer:new e},this.blocks.set(t.reasoningId,r)}const o=r.buffer.append(i);o&&this.publish(r.id,o)}end(e){const s=this.blocks.get(e);this.blocks.delete(e);const t=s?.buffer.finish();s&&t&&this.publish(s.id,t)}finish(){for(const e of this.blocks.keys())this.end(e);this.reset()}reset(){this.blocks.clear(),this.overflowed=!1}}
@@ -23,6 +23,10 @@ export type ContextCompactionFailure = {
23
23
  } | {
24
24
  readonly reason: typeof COMPACTION_FAILURE_REASONS.error;
25
25
  };
26
+ export interface ReasoningPresentation {
27
+ readonly kind: "summary" | "text";
28
+ readonly readDeltas: (nativeChunk: unknown) => readonly string[];
29
+ }
26
30
  export type SessionEvent = {
27
31
  readonly type: "context-recovery";
28
32
  readonly state: ContextRecoveryView | null;
@@ -50,6 +54,7 @@ export type SessionEvent = {
50
54
  readonly reasoningId: string;
51
55
  } | {
52
56
  readonly type: "reasoning-delta";
57
+ readonly presentation?: ReasoningPresentation["kind"];
53
58
  readonly reasoningId: string;
54
59
  readonly delta: string;
55
60
  } | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roll-agent/runtime",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,7 +40,7 @@
40
40
  "dependencies": {
41
41
  "@ai-sdk/provider": "4.0.31",
42
42
  "@modelcontextprotocol/sdk": "1.32.0",
43
- "@roll-agent/protocol": "0.10.0",
43
+ "@roll-agent/protocol": "0.11.0",
44
44
  "@vscode/ripgrep": "1.18.0",
45
45
  "ai": "7.0.146",
46
46
  "diff": "9.0.0",