@x-otto/session-contract 0.0.1-alpha.2 → 0.0.1-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -613,7 +613,7 @@ interface ResidencyBudgetConfig {
613
613
  * RFC-323 M4:合并 settings 覆盖到 env/默认常量之上,产出完整的 ResidencyBudgetConfig。
614
614
  *
615
615
  * 优先级:**env(上方常量,已含 env 覆盖)> settings > 默认**。
616
- * 实现:常量本身已是 `normalizeEnv(env, 默认)` 的结果——若用户设了 env,常量即为 env 值;
616
+ * 实现:常量本身已是 `parsePositiveIntEnv(env, 默认)` 的结果——若用户设了 env,常量即为 env 值;
617
617
  * 否则为默认值。settings 只在"用户**没设 env**"时生效——但模块层无法区分"常量是 env 值
618
618
  * 还是默认值"。故约定:**settings 值优先于常量默认,但 env 显式设置时由调用方保证不传
619
619
  * settings**(见 app 层 `resolveResidencySettingsOverride`:仅当对应 env 未设时才取 settings)。
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/project.ts","../src/requests.ts","../src/frontend-port.ts","../src/constants.ts","../src/pulse-survey-trigger.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/project.ts","../src/requests.ts","../src/frontend-port.ts","../src/constants.ts","../src/pulse-survey-trigger.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{normalizeEnv as e}from"@x-otto/env";function t(){return{delegated:new Map,todoList:[],currentTurn:0}}const n=new Set([`task_delegate`,`team_run`,`fork_call`]);function r(e,t){if(t.tracked===!1||(typeof t.mode==`string`?t.mode:`sync`)!==`sync`)return!1;let n=Array.isArray(t.taskIds)?t.taskIds.filter(e=>typeof e==`string`):void 0,r;if(n&&n.length>0)r=n.filter(t=>e.todoList.some(e=>e.id===t&&e.status!==`done`));else{let t=e.todoList.filter(e=>e.status===`in_progress`);r=t.length===1?[t[0].id]:[]}return r.length===0?!1:(e.todoList=e.todoList.map(e=>e.id!=null&&r.includes(e.id)?{...e,status:`done`}:e),!0)}function i(e,t,i={}){let o=e.sessionId,s=i.isDelegationTool??(e=>n.has(e));switch(e.type){case`prompt.start`:return t.currentTurn++,[{sessionId:o,kind:`prompt.start`,text:e.text}];case`prompt.end`:{t.delegated.clear();let n=i.cacheHitRatio?.();return[{sessionId:o,kind:`delegate.update`,tasks:[]},{sessionId:o,kind:`prompt.end`,model:e.model??i.currentModel?.()??``,tokens:i.turnTokens?.(),cacheHitRatio:n??void 0,effort:e.thinkingLevel,stopReason:e.stopReason}]}case`turn.start`:return[{sessionId:o,kind:`turn.budget`,toolTurnCount:e.toolTurnCount,maxToolTurns:e.maxToolTurns,outputTokens:e.promptOutputTokens,outputTokenBudget:e.promptOutputTokenBudget}];case`stream.event`:{let t=e.event;switch(t.type){case`text_delta`:return[{sessionId:o,kind:`stream.text.delta`,delta:t.delta??``}];case`thinking_delta`:return[{sessionId:o,kind:`stream.thinking.delta`,delta:t.delta??``}];case`text_start`:return[{sessionId:o,kind:`stream.text.start`}];case`text_end`:return[{sessionId:o,kind:`stream.text.end`}];case`thinking_start`:return[{sessionId:o,kind:`stream.thinking.start`}];case`thinking_end`:return[{sessionId:o,kind:`stream.thinking.end`}];case`error`:return[{sessionId:o,kind:`error`,message:a(t.error),code:`STREAM_ERROR`}];case`start`:case`tool_call_start`:case`tool_call_delta`:case`tool_call_end`:case`done`:return[];default:return[]}}case`tool.call.start`:{let n=e.toolCall,r=[{sessionId:o,kind:`tool.start`,call:n}];if(s(n.name)){let e=n.arguments??{},i=e.subagent??e.agent??e.category??e.team,a=typeof e.prompt==`string`?e.prompt.replace(/\n/g,` `).slice(0,48):void 0;t.delegated.set(n.id,{id:n.id,name:typeof i==`string`?i:n.name,detail:a,status:`running`}),r.push({sessionId:o,kind:`delegate.update`,tasks:[...t.delegated.values()]})}return r}case`tool.call.end`:{let{toolCall:n,isError:a}=e,s=n.arguments??{},c=t=>({sessionId:o,kind:`tool.end`,call:n,isError:a,resultText:e.resultText??i.toolResultText?.(n),resultTokensEstimate:e.resultTokensEstimate,suppressMessage:t});if(n.name===`write_todos`&&Array.isArray(s.todos)){let e=s.todos;if(s.action===`update`)for(let n of e){let e=t.todoList.findIndex(e=>e.id===n.id);e>=0?t.todoList[e]={...t.todoList[e],...n,turn:t.currentTurn}:t.todoList.push({...n,turn:t.currentTurn})}else t.todoList=e.map(e=>({...e,turn:t.currentTurn}));return[c(!0),{sessionId:o,kind:`tasks.update`,tasks:[...t.todoList],title:s.title}]}if(t.delegated.has(n.id)){let e=t.delegated.get(n.id);t.delegated.set(n.id,{...e,status:a?`error`:`done`});let i=[{sessionId:o,kind:`delegate.update`,tasks:[...t.delegated.values()]},c()];return n.name===`task_delegate`&&!a&&r(t,s)&&i.push({sessionId:o,kind:`tasks.update`,tasks:[...t.todoList]}),i}return[c()]}case`session.start`:return[{sessionId:o,kind:`session.activity`,action:`created`}];case`session.end`:return[{sessionId:o,kind:`session.activity`,action:`ended`}];case`streaming.start`:return[{sessionId:o,kind:`session.status`,status:`streaming`,model:e.model}];case`streaming.end`:{let t=e;return[{sessionId:o,kind:`session.status`,status:`idle`,model:t.model,stopReason:t.stopReason}]}case`compaction.start`:return[{sessionId:o,kind:`session.status`,status:`compacting`,messageCount:e.messageCount}];case`compaction.end`:return[{sessionId:o,kind:`session.status`,status:`idle`,retainedCount:e.retainedCount}];case`approval.required`:{let t=e;return[{sessionId:o,kind:`approval.required`,id:t.id,toolName:t.toolName,arguments:t.arguments,description:t.description,risk:t.risk}]}case`approval.resolved`:{let t=e;return[{sessionId:o,kind:`approval.resolved`,id:t.id,approved:t.approved}]}case`ask.user.required`:{let t=e;return[{sessionId:o,kind:`ask.required`,requestId:t.requestId,question:t.question}]}case`ask.user.resolved`:return[{sessionId:o,kind:`ask.resolved`,requestId:e.requestId}];case`plan.approval.required`:{let t=e;return[{sessionId:o,kind:`plan.approval.required`,requestId:t.requestId,planContent:t.planContent}]}case`plan.approval.resolved`:{let t=e;return[{sessionId:o,kind:`plan.approval.resolved`,requestId:t.requestId,action:t.action}]}case`error`:return[{sessionId:o,kind:`error`,message:a(e.error),code:`SESSION_ERROR`}];case`prompt.continued`:case`messages.persist`:case`agent.status`:case`budget.notice`:case`prompt.budget.notice`:case`progress.stall.notice`:case`tool.call.mismatch.notice`:case`session.cost-budget-exceeded`:case`turn.end`:case`memory.pruned`:case`session.cleared`:case`run.paused`:case`run.resumed`:case`run.pause_requested`:case`run.pause_cancelled`:case`session.history-capped`:case`session.write-lease-denied`:case`session.write-lease-restored`:case`session.crash-gap-detected`:case`image.vision-delegate`:case`a2ui.action`:case`compaction.reactive.notice`:case`image.degradation.notice`:case`steer.consumed`:return[];default:return[]}}function a(e){return e instanceof Error?e.message:typeof e==`string`?e:`unknown error`}function o(e){return{answer:e.recommendation,acceptedRecommendation:!0,resolvedBy:`auto_recommendation`}}function s(e,t,n){if(t.length===0&&!n)return o(e);let r=(e.options??[]).filter(e=>e.recommended).map(e=>e.label),i=r.length>0&&t.length===r.length&&t.every(e=>r.includes(e)),a=t.length>0?t.join(`, `):``;return{answer:n?a?`${a}\n\n补充信息:${n}`:n:a,selectedOptionLabels:t.length>0?t:void 0,acceptedRecommendation:i,resolvedBy:`human`,freeformText:n}}function c(e,t){let n=t?.trim();return n?{answer:n,acceptedRecommendation:n===e.recommendation,resolvedBy:`human`}:o(e)}function l(e,t,n){return typeof e!=`string`||!e.includes(n)?null:(typeof t?.command==`string`?t.command:``)||null}const u=e(process.env.OTTO_SESSION_MAX_HISTORY_MESSAGES,5e4),d=e(process.env.OTTO_SESSION_MAX_CONTENT_BYTES,64*1024*1024),f=e(process.env.OTTO_SESSION_RESUME_WINDOW_MESSAGES,5e3),p=e(process.env.OTTO_SESSION_COMPACTION_TIMEOUT_MS,3e4),m=e(process.env.OTTO_SESSION_TOTAL_RESIDENCY_BUDGET,1024*1024*1024),h=e(process.env.OTTO_SESSION_MIN_PER_SESSION_BYTES,16*1024*1024),g=e(process.env.OTTO_SESSION_MAX_PER_SESSION_BYTES,1024*1024*1024);function _(e){return{totalBytes:e?.totalBytes??m,minPerSessionBytes:e?.minPerSessionBytes??h,maxPerSessionBytes:e?.maxPerSessionBytes??g,maxContentBytes:e?.maxContentBytes??d,maxHistoryMessages:e?.maxHistoryMessages??u,resumeWindowMessages:e?.resumeWindowMessages??f,compactionTimeoutMs:e?.compactionTimeoutMs??p}}function v(e,t,n,r=Math.random){return!t.enabled||t.forcedUpgradeActive||n.lastShownTurn!==void 0&&e-n.lastShownTurn<t.minTurnGap?!1:r()<t.probability}export{n as DEFAULT_DELEGATION_TOOLS,p as SESSION_COMPACTION_TIMEOUT_MS,d as SESSION_MAX_CONTENT_BYTES,u as SESSION_MAX_HISTORY_MESSAGES,g as SESSION_MAX_PER_SESSION_BYTES,h as SESSION_MIN_PER_SESSION_BYTES,f as SESSION_RESUME_WINDOW_MESSAGES,m as SESSION_TOTAL_RESIDENCY_BUDGET,o as autoAdoptAnswer,t as createProjectorState,i as projectSessionEvent,s as resolveChoiceAnswer,_ as resolveResidencyBudget,c as resolveTextAnswer,l as sandboxBypassCommand,v as shouldShowPulseSurvey};
1
+ function e(){return{delegated:new Map,todoList:[],currentTurn:0}}const t=new Set([`task_delegate`,`team_run`,`fork_call`]);function n(e,t){if(t.tracked===!1||(typeof t.mode==`string`?t.mode:`sync`)!==`sync`)return!1;let n=Array.isArray(t.taskIds)?t.taskIds.filter(e=>typeof e==`string`):void 0,r;if(n&&n.length>0)r=n.filter(t=>e.todoList.some(e=>e.id===t&&e.status!==`done`));else{let t=e.todoList.filter(e=>e.status===`in_progress`);r=t.length===1?[t[0].id]:[]}return r.length===0?!1:(e.todoList=e.todoList.map(e=>e.id!=null&&r.includes(e.id)?{...e,status:`done`}:e),!0)}function r(e,r,a={}){let o=e.sessionId,s=a.isDelegationTool??(e=>t.has(e));switch(e.type){case`prompt.start`:return r.currentTurn++,[{sessionId:o,kind:`prompt.start`,text:e.text}];case`prompt.end`:{r.delegated.clear();let t=a.cacheHitRatio?.();return[{sessionId:o,kind:`delegate.update`,tasks:[]},{sessionId:o,kind:`prompt.end`,model:e.model??a.currentModel?.()??``,tokens:a.turnTokens?.(),cacheHitRatio:t??void 0,effort:e.thinkingLevel,stopReason:e.stopReason}]}case`turn.start`:return[{sessionId:o,kind:`turn.budget`,toolTurnCount:e.toolTurnCount,maxToolTurns:e.maxToolTurns,outputTokens:e.promptOutputTokens,outputTokenBudget:e.promptOutputTokenBudget}];case`stream.event`:{let t=e.event;switch(t.type){case`text_delta`:return[{sessionId:o,kind:`stream.text.delta`,delta:t.delta??``}];case`thinking_delta`:return[{sessionId:o,kind:`stream.thinking.delta`,delta:t.delta??``}];case`text_start`:return[{sessionId:o,kind:`stream.text.start`}];case`text_end`:return[{sessionId:o,kind:`stream.text.end`}];case`thinking_start`:return[{sessionId:o,kind:`stream.thinking.start`}];case`thinking_end`:return[{sessionId:o,kind:`stream.thinking.end`}];case`error`:return[{sessionId:o,kind:`error`,message:i(t.error),code:`STREAM_ERROR`}];case`start`:case`tool_call_start`:case`tool_call_delta`:case`tool_call_end`:case`done`:return[];default:return[]}}case`tool.call.start`:{let t=e.toolCall,n=[{sessionId:o,kind:`tool.start`,call:t}];if(s(t.name)){let e=t.arguments??{},i=e.subagent??e.agent??e.category??e.team,a=typeof e.prompt==`string`?e.prompt.replace(/\n/g,` `).slice(0,48):void 0;r.delegated.set(t.id,{id:t.id,name:typeof i==`string`?i:t.name,detail:a,status:`running`}),n.push({sessionId:o,kind:`delegate.update`,tasks:[...r.delegated.values()]})}return n}case`tool.call.end`:{let{toolCall:t,isError:i}=e,s=t.arguments??{},c=n=>({sessionId:o,kind:`tool.end`,call:t,isError:i,resultText:e.resultText??a.toolResultText?.(t),resultTokensEstimate:e.resultTokensEstimate,suppressMessage:n});if(t.name===`write_todos`&&Array.isArray(s.todos)){let e=s.todos;if(s.action===`update`)for(let t of e){let e=r.todoList.findIndex(e=>e.id===t.id);e>=0?r.todoList[e]={...r.todoList[e],...t,turn:r.currentTurn}:r.todoList.push({...t,turn:r.currentTurn})}else r.todoList=e.map(e=>({...e,turn:r.currentTurn}));return[c(!0),{sessionId:o,kind:`tasks.update`,tasks:[...r.todoList],title:s.title}]}if(r.delegated.has(t.id)){let e=r.delegated.get(t.id);r.delegated.set(t.id,{...e,status:i?`error`:`done`});let a=[{sessionId:o,kind:`delegate.update`,tasks:[...r.delegated.values()]},c()];return t.name===`task_delegate`&&!i&&n(r,s)&&a.push({sessionId:o,kind:`tasks.update`,tasks:[...r.todoList]}),a}return[c()]}case`session.start`:return[{sessionId:o,kind:`session.activity`,action:`created`}];case`session.end`:return[{sessionId:o,kind:`session.activity`,action:`ended`}];case`streaming.start`:return[{sessionId:o,kind:`session.status`,status:`streaming`,model:e.model}];case`streaming.end`:{let t=e;return[{sessionId:o,kind:`session.status`,status:`idle`,model:t.model,stopReason:t.stopReason}]}case`compaction.start`:return[{sessionId:o,kind:`session.status`,status:`compacting`,messageCount:e.messageCount}];case`compaction.end`:return[{sessionId:o,kind:`session.status`,status:`idle`,retainedCount:e.retainedCount}];case`approval.required`:{let t=e;return[{sessionId:o,kind:`approval.required`,id:t.id,toolName:t.toolName,arguments:t.arguments,description:t.description,risk:t.risk}]}case`approval.resolved`:{let t=e;return[{sessionId:o,kind:`approval.resolved`,id:t.id,approved:t.approved}]}case`ask.user.required`:{let t=e;return[{sessionId:o,kind:`ask.required`,requestId:t.requestId,question:t.question}]}case`ask.user.resolved`:return[{sessionId:o,kind:`ask.resolved`,requestId:e.requestId}];case`plan.approval.required`:{let t=e;return[{sessionId:o,kind:`plan.approval.required`,requestId:t.requestId,planContent:t.planContent}]}case`plan.approval.resolved`:{let t=e;return[{sessionId:o,kind:`plan.approval.resolved`,requestId:t.requestId,action:t.action}]}case`error`:return[{sessionId:o,kind:`error`,message:i(e.error),code:`SESSION_ERROR`}];case`prompt.continued`:case`messages.persist`:case`agent.status`:case`budget.notice`:case`prompt.budget.notice`:case`progress.stall.notice`:case`tool.call.mismatch.notice`:case`session.cost-budget-exceeded`:case`turn.end`:case`memory.pruned`:case`session.cleared`:case`run.paused`:case`run.resumed`:case`run.pause_requested`:case`run.pause_cancelled`:case`session.history-capped`:case`session.write-lease-denied`:case`session.write-lease-restored`:case`session.crash-gap-detected`:case`image.vision-delegate`:case`a2ui.action`:case`compaction.reactive.notice`:case`image.degradation.notice`:case`steer.consumed`:return[];default:return[]}}function i(e){return e instanceof Error?e.message:typeof e==`string`?e:`unknown error`}function a(e){return{answer:e.recommendation,acceptedRecommendation:!0,resolvedBy:`auto_recommendation`}}function o(e,t,n){if(t.length===0&&!n)return a(e);let r=(e.options??[]).filter(e=>e.recommended).map(e=>e.label),i=r.length>0&&t.length===r.length&&t.every(e=>r.includes(e)),o=t.length>0?t.join(`, `):``;return{answer:n?o?`${o}\n\n补充信息:${n}`:n:o,selectedOptionLabels:t.length>0?t:void 0,acceptedRecommendation:i,resolvedBy:`human`,freeformText:n}}function s(e,t){let n=t?.trim();return n?{answer:n,acceptedRecommendation:n===e.recommendation,resolvedBy:`human`}:a(e)}function c(e,t,n){return typeof e!=`string`||!e.includes(n)?null:(typeof t?.command==`string`?t.command:``)||null}function l(e,t){if(e===void 0)return t;let n=parseInt(e,10);return isNaN(n)||n<=0?t:n}const u=l(process.env.OTTO_SESSION_MAX_HISTORY_MESSAGES,5e4),d=l(process.env.OTTO_SESSION_MAX_CONTENT_BYTES,64*1024*1024),f=l(process.env.OTTO_SESSION_RESUME_WINDOW_MESSAGES,5e3),p=l(process.env.OTTO_SESSION_COMPACTION_TIMEOUT_MS,3e4),m=l(process.env.OTTO_SESSION_TOTAL_RESIDENCY_BUDGET,1024*1024*1024),h=l(process.env.OTTO_SESSION_MIN_PER_SESSION_BYTES,16*1024*1024),g=l(process.env.OTTO_SESSION_MAX_PER_SESSION_BYTES,1024*1024*1024);function _(e){return{totalBytes:e?.totalBytes??m,minPerSessionBytes:e?.minPerSessionBytes??h,maxPerSessionBytes:e?.maxPerSessionBytes??g,maxContentBytes:e?.maxContentBytes??d,maxHistoryMessages:e?.maxHistoryMessages??u,resumeWindowMessages:e?.resumeWindowMessages??f,compactionTimeoutMs:e?.compactionTimeoutMs??p}}function v(e,t,n,r=Math.random){return!t.enabled||t.forcedUpgradeActive||n.lastShownTurn!==void 0&&e-n.lastShownTurn<t.minTurnGap?!1:r()<t.probability}export{t as DEFAULT_DELEGATION_TOOLS,p as SESSION_COMPACTION_TIMEOUT_MS,d as SESSION_MAX_CONTENT_BYTES,u as SESSION_MAX_HISTORY_MESSAGES,g as SESSION_MAX_PER_SESSION_BYTES,h as SESSION_MIN_PER_SESSION_BYTES,f as SESSION_RESUME_WINDOW_MESSAGES,m as SESSION_TOTAL_RESIDENCY_BUDGET,a as autoAdoptAnswer,e as createProjectorState,r as projectSessionEvent,o as resolveChoiceAnswer,_ as resolveResidencyBudget,s as resolveTextAnswer,c as sandboxBypassCommand,v as shouldShowPulseSurvey};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/project.ts","../src/requests.ts","../src/constants.ts","../src/pulse-survey-trigger.ts"],"sourcesContent":["/**\n * project.ts — 投影器:AgentSessionEvent/StreamEvent 子集 → SessionEvent[](前端无关事实)。\n *\n * 忠实复刻 cli.ts `session.subscribe` 同步部分。**投影器持有集合累加器**(delegated Map /\n * todoList),发 snapshot —— 合并逻辑只此一份,不让消费端各抄一遍。流式累加归 reducer(消费端)。\n */\nimport type { AgentSessionEvent } from '@x-otto/interchange'\n\nimport type {\n SessionEvent,\n ProjectCtx,\n TaskItem,\n DelegatedTask,\n DelegatedArg,\n} from './types'\n\n// 直接用 ./types 的 canonical TaskItem/DelegatedTask 作累加器元素类型,\n// 取代本地结构同形的重声明(Todo/DelegatedEntry)——后者逼出 `as unknown as DelegatedArg/TaskItemArg`\n// 桥接「同形异名」。统一后 `[...values()]` 直接是 DelegatedArg/TaskItemArg,casts 全消。\nexport interface ProjectorState {\n delegated: Map<string, DelegatedTask>\n todoList: TaskItem[]\n /** 当前回合编号(1-based)。prompt.start 时自增。 */\n currentTurn: number\n}\nexport function createProjectorState(): ProjectorState {\n return { delegated: new Map(), todoList: [], currentTurn: 0 }\n}\n\nexport const DEFAULT_DELEGATION_TOOLS = new Set(['task_delegate', 'team_run', 'fork_call'])\n\n/**\n * 子代理完成后的 todo 自动同步——宿主侧规则的投影镜像(真源:tools/orchestration/\n * dispatched-task.ts `syncTodosOnSubagentComplete`,两处规则必须一致):\n * - 仅 sync 模式且 tracked !== false(background 终态未知;fork/team 走旁路不经宿主同步;\n * untracked 走 callAgent 旁路也不经——RFC-302 D8);\n * - taskIds 显式指定 → 只标这些未 done 的项为 done;\n * - 未指定且恰好一个 in_progress → 标它 done;\n * - 其余(0 或多 in_progress)不同步。\n * 返回是否发生了变更(据此决定是否发 tasks.update)。\n */\nfunction applyDelegateTodoSync(state: ProjectorState, args: Record<string, unknown>): boolean {\n // RFC-302 D8:untracked(tracked:false)走 callAgent 旁路,宿主侧不经\n // syncTodosOnSubagentComplete——镜像必须同门,否则 TUI/session metadata 误标 done。\n if (args.tracked === false) return false\n const mode = typeof args.mode === 'string' ? args.mode : 'sync'\n if (mode !== 'sync') return false\n\n const taskIds = Array.isArray(args.taskIds)\n ? (args.taskIds as unknown[]).filter((x): x is string => typeof x === 'string')\n : undefined\n\n let targetIds: string[]\n if (taskIds && taskIds.length > 0) {\n targetIds = taskIds.filter((id) =>\n state.todoList.some((t) => t.id === id && t.status !== 'done'),\n )\n } else {\n const inProgress = state.todoList.filter((t) => t.status === 'in_progress')\n targetIds = inProgress.length === 1 ? [inProgress[0]!.id!] : []\n }\n if (targetIds.length === 0) return false\n\n state.todoList = state.todoList.map((t) =>\n t.id != null && targetIds.includes(t.id) ? { ...t, status: 'done' as const } : t,\n )\n return true\n}\n\nexport function projectSessionEvent(\n event: AgentSessionEvent,\n state: ProjectorState,\n ctx: ProjectCtx = {},\n): SessionEvent[] {\n const sessionId = event.sessionId\n const isDelegation = ctx.isDelegationTool ?? ((n: string) => DEFAULT_DELEGATION_TOOLS.has(n))\n\n switch (event.type) {\n case 'prompt.start':\n state.currentTurn++\n return [\n {\n sessionId,\n kind: 'prompt.start',\n text: event.text,\n },\n ]\n\n case 'prompt.end': {\n state.delegated.clear()\n const ratio = ctx.cacheHitRatio?.()\n return [\n { sessionId, kind: 'delegate.update', tasks: [] satisfies DelegatedArg },\n {\n sessionId,\n kind: 'prompt.end',\n // 优先用事件自带的模型快照(AgentSession 在 prompt() 入口捕获的\"这一轮实际执行模型\");\n // 缺省(旧事件/未来其它来源)时兜底走 ctx.currentModel() 惰性读取活跃 session.model。\n model: event.model ?? ctx.currentModel?.() ?? '',\n tokens: ctx.turnTokens?.(),\n cacheHitRatio: ratio == null ? undefined : ratio,\n effort: event.thinkingLevel,\n stopReason: event.stopReason,\n },\n ]\n }\n\n case 'turn.start':\n return [\n {\n sessionId,\n kind: 'turn.budget',\n toolTurnCount: event.toolTurnCount,\n maxToolTurns: event.maxToolTurns,\n outputTokens: event.promptOutputTokens,\n outputTokenBudget: event.promptOutputTokenBudget,\n },\n ]\n\n case 'stream.event': {\n const e = event.event\n switch (e.type) {\n case 'text_delta':\n return [{ sessionId, kind: 'stream.text.delta', delta: e.delta ?? '' }]\n case 'thinking_delta':\n return [{ sessionId, kind: 'stream.thinking.delta', delta: e.delta ?? '' }]\n case 'text_start':\n return [{ sessionId, kind: 'stream.text.start' }]\n case 'text_end':\n return [{ sessionId, kind: 'stream.text.end' }]\n case 'thinking_start':\n return [{ sessionId, kind: 'stream.thinking.start' }]\n case 'thinking_end':\n return [{ sessionId, kind: 'stream.thinking.end' }]\n case 'error':\n return [{ sessionId, kind: 'error', message: errMessage(e.error), code: 'STREAM_ERROR' }]\n // 08-12 review W5:以下成员**有意不投影**(与 AgentSessionEvent 投影的「显式空\n // case + 穷举 default」纪律对齐)——此前它们静默落入 `default: return []`,\n // 新增 StreamEvent 成员时编译器不会提示投影器漏处理(静默丢弃盲区)。\n // - start/tool_call_start/tool_call_delta/tool_call_end:工具调用细节经独立的\n // tool.call.start/end AgentSessionEvent 投影,不经 stream.event 透传;\n // - done:回合完成经 prompt.end/turn.budget AgentSessionEvent 投影(含\n // usage/stopReason/model),不经 stream.event 透传。\n case 'start':\n case 'tool_call_start':\n case 'tool_call_delta':\n case 'tool_call_end':\n case 'done':\n return []\n default: {\n // 编译期穷举守卫:e 在所有显式 case 之后应为 never。新增 StreamEvent 成员\n // 漏写 case 时这行赋值报 TS2322,指向本文件强制处理(与外层 switch 同纪律)。\n const _exhaustive: never = e\n void _exhaustive\n return []\n }\n }\n }\n\n case 'tool.call.start': {\n const call = event.toolCall\n const out: SessionEvent[] = [{ sessionId, kind: 'tool.start', call }]\n if (isDelegation(call.name)) {\n const a = call.arguments ?? {}\n const label = a.subagent ?? a.agent ?? a.category ?? a.team\n const detail =\n typeof a.prompt === 'string' ? a.prompt.replace(/\\n/g, ' ').slice(0, 48) : undefined\n state.delegated.set(call.id, {\n id: call.id,\n name: typeof label === 'string' ? label : call.name,\n detail,\n status: 'running',\n })\n out.push({\n sessionId,\n kind: 'delegate.update',\n tasks: [...state.delegated.values()],\n })\n }\n return out\n }\n\n case 'tool.call.end': {\n const { toolCall: call, isError } = event\n const args = call.arguments ?? {}\n const mkToolEnd = (suppressMessage?: boolean): SessionEvent => ({\n sessionId,\n kind: 'tool.end',\n call,\n isError,\n // 残影修复(2026-07):优先用事件自带的 resultText(按本次 toolCall 精确对应,\n // AgentSession.onToolCallEnd 在产生处构造)。ctx.toolResultText 仅作旧数据兼容\n // 回退(如 replay 老 trace 无该字段的场景)——它从 session.messages() 倒查\"最后\n // 一条 tool_result\",在并行/异步工具场景下会与当前 call 错配(残影根因),新代码\n // 路径不应再依赖它。\n resultText: event.resultText ?? ctx.toolResultText?.(call),\n resultTokensEstimate: event.resultTokensEstimate,\n suppressMessage,\n })\n\n if (call.name === 'write_todos' && Array.isArray(args.todos)) {\n // 边界:write_todos 工具实参是未定型 wire 数据;此处单点定型为 TaskItem[]。\n const incoming = args.todos as TaskItem[]\n if (args.action === 'update') {\n for (const t of incoming) {\n const i = state.todoList.findIndex((x) => x.id === t.id)\n if (i >= 0) state.todoList[i] = { ...state.todoList[i], ...t, turn: state.currentTurn }\n else state.todoList.push({ ...t, turn: state.currentTurn })\n }\n } else {\n state.todoList = incoming.map((t) => ({ ...t, turn: state.currentTurn }))\n }\n return [\n mkToolEnd(true),\n {\n sessionId,\n kind: 'tasks.update',\n tasks: [...state.todoList],\n title: args.title as string | undefined,\n },\n ]\n }\n\n if (state.delegated.has(call.id)) {\n const task = state.delegated.get(call.id)!\n state.delegated.set(call.id, { ...task, status: isError ? 'error' : 'done' })\n const out: SessionEvent[] = [\n {\n sessionId,\n kind: 'delegate.update',\n tasks: [...state.delegated.values()],\n },\n mkToolEnd(),\n ]\n // 镜像宿主的子代理 todo 自动同步(tools/orchestration/dispatched-task.ts\n // syncTodosOnSubagentComplete):该同步直调 orchestrator.writeTodos、不产生\n // write_todos 工具事件,若不在此镜像,TUI 面板与 session metadata 永远收不到\n // (泄漏根因)。规则两处必须一致:仅 sync 模式 + 非错误;taskIds 显式 → 标这些项\n // done;未指定且恰好一个 in_progress → 标它 done;其余不动。\n if (call.name === 'task_delegate' && !isError) {\n const synced = applyDelegateTodoSync(state, args)\n if (synced) {\n out.push({ sessionId, kind: 'tasks.update', tasks: [...state.todoList] })\n }\n }\n return out\n }\n\n return [mkToolEnd()]\n }\n\n // —— 会话生命周期 / 状态 ——\n case 'session.start':\n return [{ sessionId, kind: 'session.activity', action: 'created' }]\n case 'session.end':\n return [{ sessionId, kind: 'session.activity', action: 'ended' }]\n case 'streaming.start': {\n const e = event\n return [{ sessionId, kind: 'session.status', status: 'streaming', model: e.model }]\n }\n case 'streaming.end': {\n const e = event\n return [\n { sessionId, kind: 'session.status', status: 'idle', model: e.model, stopReason: e.stopReason },\n ]\n }\n case 'compaction.start': {\n const e = event\n return [{ sessionId, kind: 'session.status', status: 'compacting', messageCount: e.messageCount }]\n }\n case 'compaction.end': {\n const e = event\n return [{ sessionId, kind: 'session.status', status: 'idle', retainedCount: e.retainedCount }]\n }\n\n // —— HITL(审批 / 问询 / 计划批准)——\n case 'approval.required': {\n const e = event\n return [\n {\n sessionId,\n kind: 'approval.required',\n id: e.id,\n toolName: e.toolName,\n arguments: e.arguments,\n description: e.description,\n risk: e.risk,\n },\n ]\n }\n case 'approval.resolved': {\n const e = event\n return [{ sessionId, kind: 'approval.resolved', id: e.id, approved: e.approved }]\n }\n case 'ask.user.required': {\n const e = event\n return [{ sessionId, kind: 'ask.required', requestId: e.requestId, question: e.question }]\n }\n case 'ask.user.resolved': {\n const e = event\n return [{ sessionId, kind: 'ask.resolved', requestId: e.requestId }]\n }\n case 'plan.approval.required': {\n const e = event\n return [\n { sessionId, kind: 'plan.approval.required', requestId: e.requestId, planContent: e.planContent },\n ]\n }\n case 'plan.approval.resolved': {\n const e = event\n return [{ sessionId, kind: 'plan.approval.resolved', requestId: e.requestId, action: e.action }]\n }\n\n // —— 错误 ——\n case 'error': {\n const e = event\n return [{ sessionId, kind: 'error', message: errMessage(e.error), code: 'SESSION_ERROR' }]\n }\n\n // —— 有意不投影的事件(终局审查 2026-07-18 S1:显式列出 + never 穷举守卫)——\n // 此前这些类型静默落入 `default: return []`——问题是新增 AgentSessionEvent 成员时\n // 编译器不会提示投影器漏了处理(静默丢弃,前端永远看不到)。显式空 case + default\n // never 断言后:interchange 新增事件类型 → 此 switch 编译失败 → 强制显式决策\n // (投影 or 声明不投影),\"漏投影\"从运行时静默 bug 变为编译期错误。\n case 'prompt.continued': // TUI 经 AgentSessionEvent 直接消费(todo 闸门续跑提示),无 SessionEvent 投影\n case 'messages.persist': // 持久化内部信号,非用户可见事实\n case 'agent.status': // 引擎状态机内部迁移,前端消费 streaming.start/end 粒度即可\n case 'budget.notice': // TUI 经原始事件直接消费(预算提示条)\n case 'prompt.budget.notice': // 同上\n case 'progress.stall.notice': // RFC-203:早期停滞检出提示,TUI 经原始事件直接消费(同 budget.notice 纹理)\n case 'tool.call.mismatch.notice': // RFC-232:工具调用协议违约提示,TUI 经原始事件直接消费(同上纹理)\n case 'session.cost-budget-exceeded': // RFC-204:会话成本预算提醒,TUI 经原始事件直接消费(同上纹理)\n case 'turn.end': // turn.start 已携带回合边界信息,end 无增量事实\n case 'memory.pruned': // 裁剪可观测性走 trace,非会话转录事实\n case 'session.cleared': // clear 由发起端(命令层)自行反馈,投影层无需重复\n case 'run.paused': // 暂停/恢复由 TUI 经原始事件消费(RFC-180)\n case 'run.resumed':\n case 'run.pause_requested': // 暂停请求/取消同上(RFC-186 D2/D4 事件拆分;feae2243 加事件时漏补本穷举)\n case 'run.pause_cancelled':\n case 'session.history-capped': // 驻留裁剪可观测性由 TUI/trace 经原始事件消费(RFC-178)\n case 'session.write-lease-denied': // 写租约状态由 TUI 经原始事件 toast(RFC-159 D3)\n case 'session.write-lease-restored':\n case 'session.crash-gap-detected': // 崩溃丢失对账告警由 TUI 经原始事件 toast(RFC-305 D3)\n case 'image.vision-delegate': // 视觉委托统计由 TUI 经原始事件消费(RFC-181)\n case 'a2ui.action': // A2UI 组件动作由面板宿主经原始事件消费(RFC-105 D6)\n case 'compaction.reactive.notice': // 反应式压缩由 TUI 经原始事件消费(终局 review 2026-07-21,复用 compact_boundary/compactionLog)\n case 'image.degradation.notice': // 图片降级兜底由 TUI 经原始事件消费 toast(终局 review 2026-07-21)\n case 'steer.consumed': // RFC-337 D3:steer 待定回显转正信号,TUI 经原始事件直接消费(commitPendingSteer);web/service 前端无 pendingSteer UI 概念,无投影\n return []\n\n default: {\n // 编译期穷举守卫:event 在所有显式 case 之后应为 never。新增事件类型漏写 case 时\n // 这行赋值报 TS2322,指向本文件强制处理。\n const _exhaustive: never = event\n void _exhaustive\n return []\n }\n }\n}\n\nfunction errMessage(err: unknown): string {\n if (err instanceof Error) return err.message\n if (typeof err === 'string') return err\n return 'unknown error'\n}\n","/**\n * requests.ts — 请求子通道的**纯决策逻辑**(ask_user 自动采纳 / approval 沙箱升级)。\n *\n * cli 的异步处理器(session.subscribe 的 ask.user.required / approval.required)仍持控制流\n * (await UI + session.resolve*),但把「该解析成什么答案」「要不要 bypass」这两段易错的安全关键\n * 决策下沉到这些纯函数 —— 可单测、对齐「取消/留空绝不悬挂工具,自动采纳推荐」纪律。\n */\n\nexport interface AskQuestionLike {\n recommendation: string\n options?: { label: string; recommended?: boolean }[]\n}\n\nexport interface AskAnswer {\n answer: string\n selectedOptionLabels?: string[]\n acceptedRecommendation: boolean\n resolvedBy: 'human' | 'auto_recommendation'\n /** grill_me allowFreeform:用户在选项之外输入的补充文字。 */\n freeformText?: string\n}\n\n/** 取消/留空 → 自动采纳推荐(resolvedBy=auto_recommendation;绝不悬挂工具)。 */\nexport function autoAdoptAnswer(q: AskQuestionLike): AskAnswer {\n return { answer: q.recommendation, acceptedRecommendation: true, resolvedBy: 'auto_recommendation' }\n}\n\n/** 单/多选题+可选自由文本:据用户已选 label(调用方须先去 ★ 装饰)解析。空选 → 自动采纳。\n * acceptedRecommendation:当且仅当选中集恰等于推荐集(非空)。 */\nexport function resolveChoiceAnswer(q: AskQuestionLike, selected: string[], freeformText?: string): AskAnswer {\n if (selected.length === 0 && !freeformText) return autoAdoptAnswer(q)\n const recommended = (q.options ?? []).filter((o) => o.recommended).map((o) => o.label)\n const accepted =\n recommended.length > 0 &&\n selected.length === recommended.length &&\n selected.every((l) => recommended.includes(l))\n const answer = selected.length > 0 ? selected.join(', ') : ''\n const fullAnswer = freeformText ? (answer ? `${answer}\\n\\n补充信息:${freeformText}` : freeformText) : answer\n return { answer: fullAnswer, selectedOptionLabels: selected.length > 0 ? selected : undefined, acceptedRecommendation: accepted, resolvedBy: 'human', freeformText }\n}\n\n/** 自由文本题:空/取消 → 自动采纳;否则人答(文本等于推荐才算采纳)。 */\nexport function resolveTextAnswer(q: AskQuestionLike, text: string | null | undefined): AskAnswer {\n const t = text?.trim()\n if (!t) return autoAdoptAnswer(q)\n return { answer: t, acceptedRecommendation: t === q.recommendation, resolvedBy: 'human' }\n}\n\n/** 沙箱升级 approval:描述带 marker 且参数含 command → 返回需 bypass 的命令,否则 null。\n * 调用方仅在「已批准」时据返回值放行(早于 resolveApproval,approval=escalated 语义)。 */\nexport function sandboxBypassCommand(\n description: unknown,\n args: Record<string, unknown> | undefined,\n marker: string,\n): string | null {\n if (typeof description !== 'string' || !description.includes(marker)) return null\n const cmd = typeof args?.command === 'string' ? args.command : ''\n return cmd || null\n}\n","import { normalizeEnv } from '@x-otto/env'\n\n/**\n * 会话历史存储**条数**上限——**结构兜底闸**(RFC-321 D7 闸位重排,2026-08-07)。\n *\n * **不是内存治理主闸**。主闸是 `SESSION_MAX_CONTENT_BYTES`(字节维度,见下);本常量\n * 只防\"条目数爆炸\"这一字节维度管不到的 CPU 问题:每回合的 token 估算 / walkBranch /\n * cap 判定都是 O(条数) 全量遍历,同样 95MB 数据下 50000 条单次扫描 1.10ms、5000 条仅\n * 0.06ms(18 倍差距,实测)——条数是独立于体积的成本维度,故保留,但退居兜底。\n *\n * **2026-08-07 由 5000 上调至 50000(RFC-321 D7)**:此前 5000 与 256MB 的临界点是\n * 52.4KB/条(256MB÷5000),而真实消息普遍小于该值 → **条数闸几乎总是抢在字节闸之前\n * 触发**(20KB/条时条数闸在 98MB 就裁,256MB 字节闸形同虚设),等于\"用一个与内存无关的\n * 数字做内存治理\"。上调后条数闸只在真正的条目爆炸(5 万条级)时介入,内存治理交还字节闸。\n *\n * **与模型上下文无关**(RFC-053 规则 1,不可削弱):上下文该看多少历史只由 token 那套\n * 决定(prune 60% + compaction 触发线,均 findCutPoint 工具对齐)。本上限只影响**内存\n * 视图**;DB 侧 append-forever(RFC-159 D1),超限会话 resume 走尾窗口加载,窗口之前的\n * 历史仍完整保留在 DB。\n *\n * **裁剪不会静默丢上下文**(RFC-321 R12):裁剪触及活跃上下文前必须先经压缩建边界,\n * 裁掉的永远是\"已被摘要覆盖的死历史\";仅当压缩连续失败达阈值才放行有损裁剪,且事件\n * 带 `lossy` 标记。历史上\"条数裁剪切在工具往返中间产生孤儿 tool_result → provider 400\"\n * 的事故(commit `7e79407f`)由 `canStartHistory` 谓词防御,与本值无关。\n */\nexport const SESSION_MAX_HISTORY_MESSAGES = normalizeEnv(\n process.env['OTTO_SESSION_MAX_HISTORY_MESSAGES'],\n 50_000,\n)\n\n/**\n * 会话消息内容字节估算预算——**回退默认值**(RFC-323 后非主闸)。\n *\n * **语义变更(2026-08-07,C5 事后 review 修正)**:本常量曾在 RFC-321 D7 被定为\n * \"内存治理主闸\"(由 256MB 下调),但 RFC-323 的 ResidencyAllocator 已成为实际主闸\n * (单会话预算 = clamp(TOTAL/N, 16MB, 256MB))。本常量随后被降级为**分配器缺席 / 注入\n * 路径未接单时的回退默认值**。它与 `SESSION_MAX_PER_SESSION_BYTES`(分配器 MAX)语义\n * 重叠且数值不同(64MB vs 256MB),是 \"同一个语义槽却有两个数字\" 的缺陷——故将其\n * 重定向为回退默认,主闸语义归分配器。\n *\n * **仍被消费处**:`storage-wiring` 给 memory 的 `maxContentBytes` 构造期静态回退(消费点\n * 实际经 `getMaxContentBytes` 注入后不走此处;getter 缺席时才用)、`history-capped`\n * 事件的 capValue 语义。未改回到 256MB 原因:避免在生产中造成恢复旧的紧预算的隐性行为\n * 变化(64MB 已有历史行为,且分配器运行时已覆盖其缺口)。\n *\n * 为什么主闸是\"字节估算\"而不是进程内存占比(`heapUsed/heapSizeLimit`)——三条实证\n * (RFC-321 R11,沿用并强化 RFC-178 §1.3 的 grill 否决):\n * 1. **归因**:heapUsed 是进程全局值。实测 200MB Buffer 泄漏全部落在 `external`,\n * heapUsed 几乎无感(0.1%);即便占比升高也无法判断该裁哪个会话——按它裁会裁掉\n * 无辜的小会话,真凶纹丝不动。字节估算逐消息累加,可归因到单会话。\n * 2. **确定性**:同一会话状态下 heapUsed 占比 8 次采样跨度 0.09 个百分点(GC 时机\n * 摆布),阈值落在波动区内会 flaky,突变门无法稳定断言。字节估算零波动。\n * 3. **可测**:JS 无 sizeof;字节估算是唯一可确定计算的内存代理。\n * heapUsed 分级仍有用武之地,但只做**阈值缩放**(RFC-178 触发器 C,`ResidencyGovernor`\n * 按 warning/critical 把 cap 除以 2/4),**永不进入触发链**(R11)。\n *\n * **口径与真实驻留的关系(实测,互异内容避开 V8 字符串共享优化)**:\n * `estimateMessageContentBytes` 计 UTF-16 code unit 数(`String.length`)。\n * - 纯 ASCII 大消息:真实堆 ≈ 估算 × 1.00(5000 条 × 60KB = 287MB 真实 / 286MB 估算)\n * - **CJK(本仓主形态):真实 ≈ 估算 × 2.05**(一个汉字 length=1 但占 2 字节)\n * 故本预算 64MB 对应最坏 ~128MB 真实驻留/会话。\n *\n * **多会话乘数(必须一并考量)**:本预算是 **per-session**,而 `SESSION_MAX=50`\n * (`@x-otto/session/constants.ts`)。理论极限 = 64MB × 50 ≈ 3.2GB 估算 / ~6.4GB 真实,\n * 靠既有 idle 驱逐与满池 LRU 驱逐兜底(非本常量职责,但调整本值时不可忽略该乘数)。\n *\n * **64MB 的取值依据(历史)**:RFC-321 曾定为“20KB/条 ≈ 3200 条触发,行为跃变小;\n * 4GB 堆下单会话占 ~3%;附件/输出形态能拦”。现为主闸分配器 MAX=256MB 的**回退默认**(见上)。\n */\nexport const SESSION_MAX_CONTENT_BYTES = normalizeEnv(\n process.env['OTTO_SESSION_MAX_CONTENT_BYTES'],\n 64 * 1024 * 1024,\n)\n\n/**\n * 会话 resume 时的**尾窗口装载条数**(RFC-321 D7 新增,与条数 cap 解耦)。\n *\n * **为什么不能复用 `SESSION_MAX_HISTORY_MESSAGES`**(此前二者同源,D7 上调 cap 后暴露):\n * cap 是\"内存里最多留多少\"的**结构兜底**(50000,只防条目爆炸);而 resume 尾窗口是\n * \"启动时一次性装载多少\",直接决定**启动耗时与首屏驻留**。实测 50000 条 × 2KB 的一次性\n * 装载 = **108MB 驻留 / 113ms**,对启动不可接受;5000 条量级(~11MB)才是合理的首屏预算。\n * 二者语义不同、约束不同,故拆为独立常量——同源是历史巧合(RFC-159 D4 立项时 cap 恰好\n * 是个\"合理的窗口大小\"),D7 闸位重排后该巧合不再成立。\n *\n * 窗口之前的历史**不丢**:DB append-forever(RFC-159 D1),可经 `/history` 分页回看\n * (`history-pager.ts`)与 RFC-300 的 DB 补页按需加载。切点仍工具边界对齐(窗口首条非\n * 孤儿 tool_result,防 provider 400,历史事故 commit `7e79407f`)。\n */\nexport const SESSION_RESUME_WINDOW_MESSAGES = normalizeEnv(\n process.env['OTTO_SESSION_RESUME_WINDOW_MESSAGES'],\n 5_000,\n)\n\n/**\n * RFC-324 D1/R5:turn-gated 压缩的超时兜底(毫秒,默认 30s,G1 已 grill 确认)。\n *\n * 逃生阀压缩 pending 时,下一回合 prompt 前会先 await 其完成;超过本值仍未完成则降级为\n * fire-and-forget 继续发 prompt——**不允许压缩未完成就永久阻塞 turn**(R5 硬约束)。\n *\n * 取值权衡:30s 覆盖正常 LLM 压缩(2-5s)+ 重试余量,超时基本等价于 LLM 故障;\n * 调小会把正常压缩误判为超时,调大则用户在 LLM 故障时等待更久。\n */\nexport const SESSION_COMPACTION_TIMEOUT_MS = normalizeEnv(\n process.env['OTTO_SESSION_COMPACTION_TIMEOUT_MS'],\n 30_000,\n)\n\n/**\n * RFC-323:进程级驻留总预算(估算口径)。\n *\n * 单会话的**有效**字节预算不再是一个固定值,而是 `clamp(TOTAL / N, MIN, MAX)`——\n * 独占时可用满 MAX,并发时自动收紧,总量始终有界。\n *\n * **1024MB 的算术依据**(CJK 最坏比值 2.05,真实上界 = 估算 × 2.05):\n *\n * | TOTAL | 真实上界 | +基线 1500MB | vs 4096MB 硬顶 |\n * |-------|---------|-------------|--------------|\n * | 1024MB | 2099MB | 3599MB | ✅ 留 ~500MB |\n * | 1280MB | 2624MB | 4124MB | ❌ 超顶 |\n *\n * 取 1024MB:极端情形(所有会话同时贴满预算)下仍留 ~500MB 余量。\n * 基线 1500MB 是 RFC-178 实测值(healthy 时 heap 已 1.5GB/4.1GB)。\n */\nexport const SESSION_TOTAL_RESIDENCY_BUDGET = normalizeEnv(\n process.env['OTTO_SESSION_TOTAL_RESIDENCY_BUDGET'],\n 1024 * 1024 * 1024,\n)\n\n/**\n * RFC-323:单会话字节预算下界(N 极大时不被摊薄到无法工作)。\n *\n * 低于此值会话会过于频繁触发压缩(每几十条消息就压一次),影响可用性。\n * `SESSION_MAX(50) × MIN(16MB) = 800MB < TOTAL(1024MB)`,故实际不可达。\n */\nexport const SESSION_MIN_PER_SESSION_BYTES = normalizeEnv(\n process.env['OTTO_SESSION_MIN_PER_SESSION_BYTES'],\n 16 * 1024 * 1024,\n)\n\n/**\n * RFC-323:单会话字节预算上界(N=1 时的封顶)。\n *\n * **2026-08-12 由 512MB 上调至 1024MB(= TOTAL)**:MAX = TOTAL 意味着单会话独占时\n * 可吃满整个进程级预算池(N=1 时 TOTAL/N=1024MB 此前被 MAX 截断)。N>1 时 TOTAL/N\n * 自然 < MAX,MAX 不生效——安全性等价于现有 TOTAL 的设计(非新增风险)。\n *\n * 安全依据(沿用 RFC-323 对 TOTAL=1024MB 的已验证算术,CJK 真实/估算 = 2.05):\n * 1024MB 估算 → 真实约 2099MB + 进程基线约 1500MB ≈ 3599MB,对 4096MB 堆硬钉\n * (`packages/cli/bin/otto.js` 的 `--max-old-space-size`)留约 497MB 余量。\n *\n * 前置条件已兑现:RFC-321 **M6 已落地**(`compaction.ts` 的窗口预检 + map-reduce\n * 分批摘要,`MEMORY_COMPACTION_INPUT_WINDOW_FRACTION=0.6`)——单次 `summarize()` 输入\n * 被机制性钳制在窗口内,**会话体积不再能撑爆压缩调用**,底线2 从\"靠预算参数保证\"\n * 升级为\"靠机制保证\"。此前保守取值(替压缩承担安全余量)已不再必要。\n *\n * **注意本值只是 clamp 的封顶,不是实得预算**:单会话实得 =\n * `clamp(TOTAL / N, MIN, MAX)`(见 `global-residency-engine.ts` 的 `decide`),\n * N 是**同一进程内**的活跃会话数(`countActiveSessionsForAllocation`,跨 otto 进程\n * 互不分摊——每个进程各有独立的 TOTAL 与独立的堆)。MAX=TOTAL 时只在 N=1 独占生效;\n * 多会话并发时仍由 TOTAL/N 摊薄,并有 `ResidencyGovernor` 的内存压力分级\n * (warning 1/2、critical 1/4)兜底。\n *\n * coverage 权衡:M6 分批路径下更大的会话体积意味着更多分段、段摘要再归约,摘要\n * 覆盖率随之下降——这是有意接受的取舍(用一定的摘要精度换取更长的原始历史驻留)。\n */\nexport const SESSION_MAX_PER_SESSION_BYTES = normalizeEnv(\n process.env['OTTO_SESSION_MAX_PER_SESSION_BYTES'],\n 1024 * 1024 * 1024,\n)\n\n/**\n * RFC-323 M4:驻留预算的运行时配置对象。\n *\n * 存在理由(D6b):上方常量在模块加载时立即求值为 number(env 快照),无法反映\n * app 启动后才 load 的 settings.json。故运行时读值点改从本对象读——由 app 层合并\n * `env(上方常量)> settings > 默认` 后注入。所有字段可选,缺省回退对应常量。\n */\nexport interface ResidencyBudgetConfig {\n totalBytes?: number\n minPerSessionBytes?: number\n maxPerSessionBytes?: number\n maxContentBytes?: number\n maxHistoryMessages?: number\n resumeWindowMessages?: number\n /**\n * RFC-324 D1/R5:turn-gated 压缩的超时兜底(毫秒)。逃生阀压缩超过此值仍未完成时,\n * 降级为 fire-and-forget——**不允许压缩未完成就永久阻塞 turn**。\n */\n compactionTimeoutMs?: number\n}\n\n/**\n * RFC-323 M4:合并 settings 覆盖到 env/默认常量之上,产出完整的 ResidencyBudgetConfig。\n *\n * 优先级:**env(上方常量,已含 env 覆盖)> settings > 默认**。\n * 实现:常量本身已是 `normalizeEnv(env, 默认)` 的结果——若用户设了 env,常量即为 env 值;\n * 否则为默认值。settings 只在\"用户**没设 env**\"时生效——但模块层无法区分\"常量是 env 值\n * 还是默认值\"。故约定:**settings 值优先于常量默认,但 env 显式设置时由调用方保证不传\n * settings**(见 app 层 `resolveResidencySettingsOverride`:仅当对应 env 未设时才取 settings)。\n */\nexport function resolveResidencyBudget(\n settings?: ResidencyBudgetConfig,\n): Required<ResidencyBudgetConfig> {\n return {\n totalBytes: settings?.totalBytes ?? SESSION_TOTAL_RESIDENCY_BUDGET,\n minPerSessionBytes: settings?.minPerSessionBytes ?? SESSION_MIN_PER_SESSION_BYTES,\n maxPerSessionBytes: settings?.maxPerSessionBytes ?? SESSION_MAX_PER_SESSION_BYTES,\n maxContentBytes: settings?.maxContentBytes ?? SESSION_MAX_CONTENT_BYTES,\n maxHistoryMessages: settings?.maxHistoryMessages ?? SESSION_MAX_HISTORY_MESSAGES,\n resumeWindowMessages: settings?.resumeWindowMessages ?? SESSION_RESUME_WINDOW_MESSAGES,\n compactionTimeoutMs: settings?.compactionTimeoutMs ?? SESSION_COMPACTION_TIMEOUT_MS,\n }\n}\n","/**\n * pulse-survey-trigger.ts — RFC-208 §2.1/§3.1:满意度脉冲调查触发判定纯函数。\n * RFC-209 M3:从 packages/cli 下沉至此(cli 与 service 均已依赖 @x-otto/session-contract,\n * 而 service 不应依赖 cli——EventBridge 需要复用本函数做 web-ui 侧 `pulse-survey.show`\n * 触发判定,见 RFC-209 milestone 执行阶段 grill 确认)。\n *\n * 纯逻辑类,不依赖 @x-otto/tui/@x-otto/coding 类型——判定「本次 prompt.end 是否应展示脉冲调查」,\n * 实际展示(tui.setPulseSurvey / web-ui pulse-survey.show)与数据写入(FeedbackRegistry)\n * 留在调用方(cli 侧 interactive-events.ts / service 侧 event-bridge.ts)。\n *\n * 触发锚点是 prompt.end(对话轮次真正结束的权威时点),按可配置概率随机抽样而非固定周期——\n * 固定周期容易被用户学习产生\"来了、又是这个\"的疲劳感;抽样配合最小回合间隔更接近\"偶尔冒出,\n * 不成为负担\"的调性。判定逻辑必须是纯函数、接受注入的 `random` 参数(RFC-208 重要事项规则 5)\n * ——不得在函数内部直接硬编码调用 `Math.random()`,保证可测试性(CLI 交互层直接用 Math.random\n * 有先例,见 draft-entries.ts,但触发判定这类需要精确验证边界值的逻辑必须可注入固定值测试)。\n *\n * `lastShownTurn` 是进程内存态,不持久化跨会话——重启 otto 后重新从零计间隔,符合\"轻量抽样,\n * 不需要跨会话精确统计\"的调性,避免为此引入额外的持久化状态文件。\n */\n\nexport interface PulseSurveyTriggerState {\n lastShownTurn?: number\n}\n\nexport interface PulseSurveyTriggerConfig {\n enabled: boolean\n probability: number\n minTurnGap: number\n /**\n * 当前是否有 Band A hard modal(如 forcedUpgrade)在场——为真时恒不触发(RFC-208 §5\n * 风险段\"forced-upgrade 并发\"缓解措施之一)。调用方传入 `modals.forcedUpgrade` 等值。\n */\n forcedUpgradeActive: boolean\n}\n\n/**\n * 判定本次 `prompt.end` 是否应展示满意度脉冲调查。\n *\n * @param currentTurn 当前对话轮次(`projState.currentTurn`)\n * @param config 触发配置(来自 `.otto/config.json` 的 `pulse_survey` 块 + 当前 Band A 状态)\n * @param state 触发状态(`lastShownTurn` 进程内存态,调用方持有并在命中时更新)\n * @param random 随机数源,默认 `Math.random`;测试注入固定值验证确定性\n */\nexport function shouldShowPulseSurvey(\n currentTurn: number,\n config: PulseSurveyTriggerConfig,\n state: PulseSurveyTriggerState,\n random: () => number = Math.random,\n): boolean {\n if (!config.enabled) return false\n if (config.forcedUpgradeActive) return false\n if (state.lastShownTurn !== undefined && currentTurn - state.lastShownTurn < config.minTurnGap) return false\n return random() < config.probability\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/project.ts","../src/requests.ts","../src/constants.ts","../src/pulse-survey-trigger.ts"],"sourcesContent":["/**\n * project.ts — 投影器:AgentSessionEvent/StreamEvent 子集 → SessionEvent[](前端无关事实)。\n *\n * 忠实复刻 cli.ts `session.subscribe` 同步部分。**投影器持有集合累加器**(delegated Map /\n * todoList),发 snapshot —— 合并逻辑只此一份,不让消费端各抄一遍。流式累加归 reducer(消费端)。\n */\nimport type { AgentSessionEvent } from '@x-otto/interchange'\n\nimport type {\n SessionEvent,\n ProjectCtx,\n TaskItem,\n DelegatedTask,\n DelegatedArg,\n} from './types'\n\n// 直接用 ./types 的 canonical TaskItem/DelegatedTask 作累加器元素类型,\n// 取代本地结构同形的重声明(Todo/DelegatedEntry)——后者逼出 `as unknown as DelegatedArg/TaskItemArg`\n// 桥接「同形异名」。统一后 `[...values()]` 直接是 DelegatedArg/TaskItemArg,casts 全消。\nexport interface ProjectorState {\n delegated: Map<string, DelegatedTask>\n todoList: TaskItem[]\n /** 当前回合编号(1-based)。prompt.start 时自增。 */\n currentTurn: number\n}\nexport function createProjectorState(): ProjectorState {\n return { delegated: new Map(), todoList: [], currentTurn: 0 }\n}\n\nexport const DEFAULT_DELEGATION_TOOLS = new Set(['task_delegate', 'team_run', 'fork_call'])\n\n/**\n * 子代理完成后的 todo 自动同步——宿主侧规则的投影镜像(真源:tools/orchestration/\n * dispatched-task.ts `syncTodosOnSubagentComplete`,两处规则必须一致):\n * - 仅 sync 模式且 tracked !== false(background 终态未知;fork/team 走旁路不经宿主同步;\n * untracked 走 callAgent 旁路也不经——RFC-302 D8);\n * - taskIds 显式指定 → 只标这些未 done 的项为 done;\n * - 未指定且恰好一个 in_progress → 标它 done;\n * - 其余(0 或多 in_progress)不同步。\n * 返回是否发生了变更(据此决定是否发 tasks.update)。\n */\nfunction applyDelegateTodoSync(state: ProjectorState, args: Record<string, unknown>): boolean {\n // RFC-302 D8:untracked(tracked:false)走 callAgent 旁路,宿主侧不经\n // syncTodosOnSubagentComplete——镜像必须同门,否则 TUI/session metadata 误标 done。\n if (args.tracked === false) return false\n const mode = typeof args.mode === 'string' ? args.mode : 'sync'\n if (mode !== 'sync') return false\n\n const taskIds = Array.isArray(args.taskIds)\n ? (args.taskIds as unknown[]).filter((x): x is string => typeof x === 'string')\n : undefined\n\n let targetIds: string[]\n if (taskIds && taskIds.length > 0) {\n targetIds = taskIds.filter((id) =>\n state.todoList.some((t) => t.id === id && t.status !== 'done'),\n )\n } else {\n const inProgress = state.todoList.filter((t) => t.status === 'in_progress')\n targetIds = inProgress.length === 1 ? [inProgress[0]!.id!] : []\n }\n if (targetIds.length === 0) return false\n\n state.todoList = state.todoList.map((t) =>\n t.id != null && targetIds.includes(t.id) ? { ...t, status: 'done' as const } : t,\n )\n return true\n}\n\nexport function projectSessionEvent(\n event: AgentSessionEvent,\n state: ProjectorState,\n ctx: ProjectCtx = {},\n): SessionEvent[] {\n const sessionId = event.sessionId\n const isDelegation = ctx.isDelegationTool ?? ((n: string) => DEFAULT_DELEGATION_TOOLS.has(n))\n\n switch (event.type) {\n case 'prompt.start':\n state.currentTurn++\n return [\n {\n sessionId,\n kind: 'prompt.start',\n text: event.text,\n },\n ]\n\n case 'prompt.end': {\n state.delegated.clear()\n const ratio = ctx.cacheHitRatio?.()\n return [\n { sessionId, kind: 'delegate.update', tasks: [] satisfies DelegatedArg },\n {\n sessionId,\n kind: 'prompt.end',\n // 优先用事件自带的模型快照(AgentSession 在 prompt() 入口捕获的\"这一轮实际执行模型\");\n // 缺省(旧事件/未来其它来源)时兜底走 ctx.currentModel() 惰性读取活跃 session.model。\n model: event.model ?? ctx.currentModel?.() ?? '',\n tokens: ctx.turnTokens?.(),\n cacheHitRatio: ratio == null ? undefined : ratio,\n effort: event.thinkingLevel,\n stopReason: event.stopReason,\n },\n ]\n }\n\n case 'turn.start':\n return [\n {\n sessionId,\n kind: 'turn.budget',\n toolTurnCount: event.toolTurnCount,\n maxToolTurns: event.maxToolTurns,\n outputTokens: event.promptOutputTokens,\n outputTokenBudget: event.promptOutputTokenBudget,\n },\n ]\n\n case 'stream.event': {\n const e = event.event\n switch (e.type) {\n case 'text_delta':\n return [{ sessionId, kind: 'stream.text.delta', delta: e.delta ?? '' }]\n case 'thinking_delta':\n return [{ sessionId, kind: 'stream.thinking.delta', delta: e.delta ?? '' }]\n case 'text_start':\n return [{ sessionId, kind: 'stream.text.start' }]\n case 'text_end':\n return [{ sessionId, kind: 'stream.text.end' }]\n case 'thinking_start':\n return [{ sessionId, kind: 'stream.thinking.start' }]\n case 'thinking_end':\n return [{ sessionId, kind: 'stream.thinking.end' }]\n case 'error':\n return [{ sessionId, kind: 'error', message: errMessage(e.error), code: 'STREAM_ERROR' }]\n // 08-12 review W5:以下成员**有意不投影**(与 AgentSessionEvent 投影的「显式空\n // case + 穷举 default」纪律对齐)——此前它们静默落入 `default: return []`,\n // 新增 StreamEvent 成员时编译器不会提示投影器漏处理(静默丢弃盲区)。\n // - start/tool_call_start/tool_call_delta/tool_call_end:工具调用细节经独立的\n // tool.call.start/end AgentSessionEvent 投影,不经 stream.event 透传;\n // - done:回合完成经 prompt.end/turn.budget AgentSessionEvent 投影(含\n // usage/stopReason/model),不经 stream.event 透传。\n case 'start':\n case 'tool_call_start':\n case 'tool_call_delta':\n case 'tool_call_end':\n case 'done':\n return []\n default: {\n // 编译期穷举守卫:e 在所有显式 case 之后应为 never。新增 StreamEvent 成员\n // 漏写 case 时这行赋值报 TS2322,指向本文件强制处理(与外层 switch 同纪律)。\n const _exhaustive: never = e\n void _exhaustive\n return []\n }\n }\n }\n\n case 'tool.call.start': {\n const call = event.toolCall\n const out: SessionEvent[] = [{ sessionId, kind: 'tool.start', call }]\n if (isDelegation(call.name)) {\n const a = call.arguments ?? {}\n const label = a.subagent ?? a.agent ?? a.category ?? a.team\n const detail =\n typeof a.prompt === 'string' ? a.prompt.replace(/\\n/g, ' ').slice(0, 48) : undefined\n state.delegated.set(call.id, {\n id: call.id,\n name: typeof label === 'string' ? label : call.name,\n detail,\n status: 'running',\n })\n out.push({\n sessionId,\n kind: 'delegate.update',\n tasks: [...state.delegated.values()],\n })\n }\n return out\n }\n\n case 'tool.call.end': {\n const { toolCall: call, isError } = event\n const args = call.arguments ?? {}\n const mkToolEnd = (suppressMessage?: boolean): SessionEvent => ({\n sessionId,\n kind: 'tool.end',\n call,\n isError,\n // 残影修复(2026-07):优先用事件自带的 resultText(按本次 toolCall 精确对应,\n // AgentSession.onToolCallEnd 在产生处构造)。ctx.toolResultText 仅作旧数据兼容\n // 回退(如 replay 老 trace 无该字段的场景)——它从 session.messages() 倒查\"最后\n // 一条 tool_result\",在并行/异步工具场景下会与当前 call 错配(残影根因),新代码\n // 路径不应再依赖它。\n resultText: event.resultText ?? ctx.toolResultText?.(call),\n resultTokensEstimate: event.resultTokensEstimate,\n suppressMessage,\n })\n\n if (call.name === 'write_todos' && Array.isArray(args.todos)) {\n // 边界:write_todos 工具实参是未定型 wire 数据;此处单点定型为 TaskItem[]。\n const incoming = args.todos as TaskItem[]\n if (args.action === 'update') {\n for (const t of incoming) {\n const i = state.todoList.findIndex((x) => x.id === t.id)\n if (i >= 0) state.todoList[i] = { ...state.todoList[i], ...t, turn: state.currentTurn }\n else state.todoList.push({ ...t, turn: state.currentTurn })\n }\n } else {\n state.todoList = incoming.map((t) => ({ ...t, turn: state.currentTurn }))\n }\n return [\n mkToolEnd(true),\n {\n sessionId,\n kind: 'tasks.update',\n tasks: [...state.todoList],\n title: args.title as string | undefined,\n },\n ]\n }\n\n if (state.delegated.has(call.id)) {\n const task = state.delegated.get(call.id)!\n state.delegated.set(call.id, { ...task, status: isError ? 'error' : 'done' })\n const out: SessionEvent[] = [\n {\n sessionId,\n kind: 'delegate.update',\n tasks: [...state.delegated.values()],\n },\n mkToolEnd(),\n ]\n // 镜像宿主的子代理 todo 自动同步(tools/orchestration/dispatched-task.ts\n // syncTodosOnSubagentComplete):该同步直调 orchestrator.writeTodos、不产生\n // write_todos 工具事件,若不在此镜像,TUI 面板与 session metadata 永远收不到\n // (泄漏根因)。规则两处必须一致:仅 sync 模式 + 非错误;taskIds 显式 → 标这些项\n // done;未指定且恰好一个 in_progress → 标它 done;其余不动。\n if (call.name === 'task_delegate' && !isError) {\n const synced = applyDelegateTodoSync(state, args)\n if (synced) {\n out.push({ sessionId, kind: 'tasks.update', tasks: [...state.todoList] })\n }\n }\n return out\n }\n\n return [mkToolEnd()]\n }\n\n // —— 会话生命周期 / 状态 ——\n case 'session.start':\n return [{ sessionId, kind: 'session.activity', action: 'created' }]\n case 'session.end':\n return [{ sessionId, kind: 'session.activity', action: 'ended' }]\n case 'streaming.start': {\n const e = event\n return [{ sessionId, kind: 'session.status', status: 'streaming', model: e.model }]\n }\n case 'streaming.end': {\n const e = event\n return [\n { sessionId, kind: 'session.status', status: 'idle', model: e.model, stopReason: e.stopReason },\n ]\n }\n case 'compaction.start': {\n const e = event\n return [{ sessionId, kind: 'session.status', status: 'compacting', messageCount: e.messageCount }]\n }\n case 'compaction.end': {\n const e = event\n return [{ sessionId, kind: 'session.status', status: 'idle', retainedCount: e.retainedCount }]\n }\n\n // —— HITL(审批 / 问询 / 计划批准)——\n case 'approval.required': {\n const e = event\n return [\n {\n sessionId,\n kind: 'approval.required',\n id: e.id,\n toolName: e.toolName,\n arguments: e.arguments,\n description: e.description,\n risk: e.risk,\n },\n ]\n }\n case 'approval.resolved': {\n const e = event\n return [{ sessionId, kind: 'approval.resolved', id: e.id, approved: e.approved }]\n }\n case 'ask.user.required': {\n const e = event\n return [{ sessionId, kind: 'ask.required', requestId: e.requestId, question: e.question }]\n }\n case 'ask.user.resolved': {\n const e = event\n return [{ sessionId, kind: 'ask.resolved', requestId: e.requestId }]\n }\n case 'plan.approval.required': {\n const e = event\n return [\n { sessionId, kind: 'plan.approval.required', requestId: e.requestId, planContent: e.planContent },\n ]\n }\n case 'plan.approval.resolved': {\n const e = event\n return [{ sessionId, kind: 'plan.approval.resolved', requestId: e.requestId, action: e.action }]\n }\n\n // —— 错误 ——\n case 'error': {\n const e = event\n return [{ sessionId, kind: 'error', message: errMessage(e.error), code: 'SESSION_ERROR' }]\n }\n\n // —— 有意不投影的事件(终局审查 2026-07-18 S1:显式列出 + never 穷举守卫)——\n // 此前这些类型静默落入 `default: return []`——问题是新增 AgentSessionEvent 成员时\n // 编译器不会提示投影器漏了处理(静默丢弃,前端永远看不到)。显式空 case + default\n // never 断言后:interchange 新增事件类型 → 此 switch 编译失败 → 强制显式决策\n // (投影 or 声明不投影),\"漏投影\"从运行时静默 bug 变为编译期错误。\n case 'prompt.continued': // TUI 经 AgentSessionEvent 直接消费(todo 闸门续跑提示),无 SessionEvent 投影\n case 'messages.persist': // 持久化内部信号,非用户可见事实\n case 'agent.status': // 引擎状态机内部迁移,前端消费 streaming.start/end 粒度即可\n case 'budget.notice': // TUI 经原始事件直接消费(预算提示条)\n case 'prompt.budget.notice': // 同上\n case 'progress.stall.notice': // RFC-203:早期停滞检出提示,TUI 经原始事件直接消费(同 budget.notice 纹理)\n case 'tool.call.mismatch.notice': // RFC-232:工具调用协议违约提示,TUI 经原始事件直接消费(同上纹理)\n case 'session.cost-budget-exceeded': // RFC-204:会话成本预算提醒,TUI 经原始事件直接消费(同上纹理)\n case 'turn.end': // turn.start 已携带回合边界信息,end 无增量事实\n case 'memory.pruned': // 裁剪可观测性走 trace,非会话转录事实\n case 'session.cleared': // clear 由发起端(命令层)自行反馈,投影层无需重复\n case 'run.paused': // 暂停/恢复由 TUI 经原始事件消费(RFC-180)\n case 'run.resumed':\n case 'run.pause_requested': // 暂停请求/取消同上(RFC-186 D2/D4 事件拆分;feae2243 加事件时漏补本穷举)\n case 'run.pause_cancelled':\n case 'session.history-capped': // 驻留裁剪可观测性由 TUI/trace 经原始事件消费(RFC-178)\n case 'session.write-lease-denied': // 写租约状态由 TUI 经原始事件 toast(RFC-159 D3)\n case 'session.write-lease-restored':\n case 'session.crash-gap-detected': // 崩溃丢失对账告警由 TUI 经原始事件 toast(RFC-305 D3)\n case 'image.vision-delegate': // 视觉委托统计由 TUI 经原始事件消费(RFC-181)\n case 'a2ui.action': // A2UI 组件动作由面板宿主经原始事件消费(RFC-105 D6)\n case 'compaction.reactive.notice': // 反应式压缩由 TUI 经原始事件消费(终局 review 2026-07-21,复用 compact_boundary/compactionLog)\n case 'image.degradation.notice': // 图片降级兜底由 TUI 经原始事件消费 toast(终局 review 2026-07-21)\n case 'steer.consumed': // RFC-337 D3:steer 待定回显转正信号,TUI 经原始事件直接消费(commitPendingSteer);web/service 前端无 pendingSteer UI 概念,无投影\n return []\n\n default: {\n // 编译期穷举守卫:event 在所有显式 case 之后应为 never。新增事件类型漏写 case 时\n // 这行赋值报 TS2322,指向本文件强制处理。\n const _exhaustive: never = event\n void _exhaustive\n return []\n }\n }\n}\n\nfunction errMessage(err: unknown): string {\n if (err instanceof Error) return err.message\n if (typeof err === 'string') return err\n return 'unknown error'\n}\n","/**\n * requests.ts — 请求子通道的**纯决策逻辑**(ask_user 自动采纳 / approval 沙箱升级)。\n *\n * cli 的异步处理器(session.subscribe 的 ask.user.required / approval.required)仍持控制流\n * (await UI + session.resolve*),但把「该解析成什么答案」「要不要 bypass」这两段易错的安全关键\n * 决策下沉到这些纯函数 —— 可单测、对齐「取消/留空绝不悬挂工具,自动采纳推荐」纪律。\n */\n\nexport interface AskQuestionLike {\n recommendation: string\n options?: { label: string; recommended?: boolean }[]\n}\n\nexport interface AskAnswer {\n answer: string\n selectedOptionLabels?: string[]\n acceptedRecommendation: boolean\n resolvedBy: 'human' | 'auto_recommendation'\n /** grill_me allowFreeform:用户在选项之外输入的补充文字。 */\n freeformText?: string\n}\n\n/** 取消/留空 → 自动采纳推荐(resolvedBy=auto_recommendation;绝不悬挂工具)。 */\nexport function autoAdoptAnswer(q: AskQuestionLike): AskAnswer {\n return { answer: q.recommendation, acceptedRecommendation: true, resolvedBy: 'auto_recommendation' }\n}\n\n/** 单/多选题+可选自由文本:据用户已选 label(调用方须先去 ★ 装饰)解析。空选 → 自动采纳。\n * acceptedRecommendation:当且仅当选中集恰等于推荐集(非空)。 */\nexport function resolveChoiceAnswer(q: AskQuestionLike, selected: string[], freeformText?: string): AskAnswer {\n if (selected.length === 0 && !freeformText) return autoAdoptAnswer(q)\n const recommended = (q.options ?? []).filter((o) => o.recommended).map((o) => o.label)\n const accepted =\n recommended.length > 0 &&\n selected.length === recommended.length &&\n selected.every((l) => recommended.includes(l))\n const answer = selected.length > 0 ? selected.join(', ') : ''\n const fullAnswer = freeformText ? (answer ? `${answer}\\n\\n补充信息:${freeformText}` : freeformText) : answer\n return { answer: fullAnswer, selectedOptionLabels: selected.length > 0 ? selected : undefined, acceptedRecommendation: accepted, resolvedBy: 'human', freeformText }\n}\n\n/** 自由文本题:空/取消 → 自动采纳;否则人答(文本等于推荐才算采纳)。 */\nexport function resolveTextAnswer(q: AskQuestionLike, text: string | null | undefined): AskAnswer {\n const t = text?.trim()\n if (!t) return autoAdoptAnswer(q)\n return { answer: t, acceptedRecommendation: t === q.recommendation, resolvedBy: 'human' }\n}\n\n/** 沙箱升级 approval:描述带 marker 且参数含 command → 返回需 bypass 的命令,否则 null。\n * 调用方仅在「已批准」时据返回值放行(早于 resolveApproval,approval=escalated 语义)。 */\nexport function sandboxBypassCommand(\n description: unknown,\n args: Record<string, unknown> | undefined,\n marker: string,\n): string | null {\n if (typeof description !== 'string' || !description.includes(marker)) return null\n const cmd = typeof args?.command === 'string' ? args.command : ''\n return cmd || null\n}\n","/**\n * 08-13 终局 review B9:契约包依赖纯净性——本包不再依赖 `@x-otto/env`。\n *\n * env 的 `normalizeEnv` 核心是\"parseInt 正整数校验 + 回退默认 + 诊断\"。契约包此前\n * 为这一语义 import 整个运行时环境包(path 常量/端口配置等无关面一并进入依赖图)。\n * 本包内联最小等价实现(8 行)。\n *\n * **诊断策略(08-13 终局复核修订)**:非法值**静默回退默认**,不做任何 stderr/警告\n * 副作用。理由:①契约包是\"纯层\",不应拥有输出副作用(env 包的延迟警告队列正是\n * RFC-324 为\"导入期裸 stderr 污染 TUI 渲染\"设计的对策——process.emitWarning 在无\n * warning 监听器时默认直接写 stderr,同样会在模块导入期触发,重新引入该回归);\n * ②这些常量是治理闸、默认值即正确基线(fail-open),诊断是边际价值且 env 包在\n * interactive 模式本就把同类 warning 丢弃。误配置的可观测性由 env 包的\n * OTTO_*_STRICT 校验与设置面板承担,不在本包职责。\n *\n * 正确性保证不变:非法/缺失值一律回退默认(fail-open,默认值即治理闸的正确基线)。\n */\nfunction parsePositiveIntEnv(value: string | undefined, defaultValue: number): number {\n if (value === undefined) return defaultValue\n const parsed = parseInt(value, 10)\n if (isNaN(parsed) || parsed <= 0) {\n return defaultValue\n }\n return parsed\n}\n\n/**\n * 会话历史存储**条数**上限——**结构兜底闸**(RFC-321 D7 闸位重排,2026-08-07)。\n *\n * **不是内存治理主闸**。主闸是 `SESSION_MAX_CONTENT_BYTES`(字节维度,见下);本常量\n * 只防\"条目数爆炸\"这一字节维度管不到的 CPU 问题:每回合的 token 估算 / walkBranch /\n * cap 判定都是 O(条数) 全量遍历,同样 95MB 数据下 50000 条单次扫描 1.10ms、5000 条仅\n * 0.06ms(18 倍差距,实测)——条数是独立于体积的成本维度,故保留,但退居兜底。\n *\n * **2026-08-07 由 5000 上调至 50000(RFC-321 D7)**:此前 5000 与 256MB 的临界点是\n * 52.4KB/条(256MB÷5000),而真实消息普遍小于该值 → **条数闸几乎总是抢在字节闸之前\n * 触发**(20KB/条时条数闸在 98MB 就裁,256MB 字节闸形同虚设),等于\"用一个与内存无关的\n * 数字做内存治理\"。上调后条数闸只在真正的条目爆炸(5 万条级)时介入,内存治理交还字节闸。\n *\n * **与模型上下文无关**(RFC-053 规则 1,不可削弱):上下文该看多少历史只由 token 那套\n * 决定(prune 60% + compaction 触发线,均 findCutPoint 工具对齐)。本上限只影响**内存\n * 视图**;DB 侧 append-forever(RFC-159 D1),超限会话 resume 走尾窗口加载,窗口之前的\n * 历史仍完整保留在 DB。\n *\n * **裁剪不会静默丢上下文**(RFC-321 R12):裁剪触及活跃上下文前必须先经压缩建边界,\n * 裁掉的永远是\"已被摘要覆盖的死历史\";仅当压缩连续失败达阈值才放行有损裁剪,且事件\n * 带 `lossy` 标记。历史上\"条数裁剪切在工具往返中间产生孤儿 tool_result → provider 400\"\n * 的事故(commit `7e79407f`)由 `canStartHistory` 谓词防御,与本值无关。\n */\nexport const SESSION_MAX_HISTORY_MESSAGES = parsePositiveIntEnv(\n process.env['OTTO_SESSION_MAX_HISTORY_MESSAGES'],\n 50_000,\n)\n\n/**\n * 会话消息内容字节估算预算——**回退默认值**(RFC-323 后非主闸)。\n *\n * **语义变更(2026-08-07,C5 事后 review 修正)**:本常量曾在 RFC-321 D7 被定为\n * \"内存治理主闸\"(由 256MB 下调),但 RFC-323 的 ResidencyAllocator 已成为实际主闸\n * (单会话预算 = clamp(TOTAL/N, 16MB, 256MB))。本常量随后被降级为**分配器缺席 / 注入\n * 路径未接单时的回退默认值**。它与 `SESSION_MAX_PER_SESSION_BYTES`(分配器 MAX)语义\n * 重叠且数值不同(64MB vs 256MB),是 \"同一个语义槽却有两个数字\" 的缺陷——故将其\n * 重定向为回退默认,主闸语义归分配器。\n *\n * **仍被消费处**:`storage-wiring` 给 memory 的 `maxContentBytes` 构造期静态回退(消费点\n * 实际经 `getMaxContentBytes` 注入后不走此处;getter 缺席时才用)、`history-capped`\n * 事件的 capValue 语义。未改回到 256MB 原因:避免在生产中造成恢复旧的紧预算的隐性行为\n * 变化(64MB 已有历史行为,且分配器运行时已覆盖其缺口)。\n *\n * 为什么主闸是\"字节估算\"而不是进程内存占比(`heapUsed/heapSizeLimit`)——三条实证\n * (RFC-321 R11,沿用并强化 RFC-178 §1.3 的 grill 否决):\n * 1. **归因**:heapUsed 是进程全局值。实测 200MB Buffer 泄漏全部落在 `external`,\n * heapUsed 几乎无感(0.1%);即便占比升高也无法判断该裁哪个会话——按它裁会裁掉\n * 无辜的小会话,真凶纹丝不动。字节估算逐消息累加,可归因到单会话。\n * 2. **确定性**:同一会话状态下 heapUsed 占比 8 次采样跨度 0.09 个百分点(GC 时机\n * 摆布),阈值落在波动区内会 flaky,突变门无法稳定断言。字节估算零波动。\n * 3. **可测**:JS 无 sizeof;字节估算是唯一可确定计算的内存代理。\n * heapUsed 分级仍有用武之地,但只做**阈值缩放**(RFC-178 触发器 C,`ResidencyGovernor`\n * 按 warning/critical 把 cap 除以 2/4),**永不进入触发链**(R11)。\n *\n * **口径与真实驻留的关系(实测,互异内容避开 V8 字符串共享优化)**:\n * `estimateMessageContentBytes` 计 UTF-16 code unit 数(`String.length`)。\n * - 纯 ASCII 大消息:真实堆 ≈ 估算 × 1.00(5000 条 × 60KB = 287MB 真实 / 286MB 估算)\n * - **CJK(本仓主形态):真实 ≈ 估算 × 2.05**(一个汉字 length=1 但占 2 字节)\n * 故本预算 64MB 对应最坏 ~128MB 真实驻留/会话。\n *\n * **多会话乘数(必须一并考量)**:本预算是 **per-session**,而 `SESSION_MAX=50`\n * (`@x-otto/session/constants.ts`)。理论极限 = 64MB × 50 ≈ 3.2GB 估算 / ~6.4GB 真实,\n * 靠既有 idle 驱逐与满池 LRU 驱逐兜底(非本常量职责,但调整本值时不可忽略该乘数)。\n *\n * **64MB 的取值依据(历史)**:RFC-321 曾定为“20KB/条 ≈ 3200 条触发,行为跃变小;\n * 4GB 堆下单会话占 ~3%;附件/输出形态能拦”。现为主闸分配器 MAX=256MB 的**回退默认**(见上)。\n */\nexport const SESSION_MAX_CONTENT_BYTES = parsePositiveIntEnv(\n process.env['OTTO_SESSION_MAX_CONTENT_BYTES'],\n 64 * 1024 * 1024,\n)\n\n/**\n * 会话 resume 时的**尾窗口装载条数**(RFC-321 D7 新增,与条数 cap 解耦)。\n *\n * **为什么不能复用 `SESSION_MAX_HISTORY_MESSAGES`**(此前二者同源,D7 上调 cap 后暴露):\n * cap 是\"内存里最多留多少\"的**结构兜底**(50000,只防条目爆炸);而 resume 尾窗口是\n * \"启动时一次性装载多少\",直接决定**启动耗时与首屏驻留**。实测 50000 条 × 2KB 的一次性\n * 装载 = **108MB 驻留 / 113ms**,对启动不可接受;5000 条量级(~11MB)才是合理的首屏预算。\n * 二者语义不同、约束不同,故拆为独立常量——同源是历史巧合(RFC-159 D4 立项时 cap 恰好\n * 是个\"合理的窗口大小\"),D7 闸位重排后该巧合不再成立。\n *\n * 窗口之前的历史**不丢**:DB append-forever(RFC-159 D1),可经 `/history` 分页回看\n * (`history-pager.ts`)与 RFC-300 的 DB 补页按需加载。切点仍工具边界对齐(窗口首条非\n * 孤儿 tool_result,防 provider 400,历史事故 commit `7e79407f`)。\n */\nexport const SESSION_RESUME_WINDOW_MESSAGES = parsePositiveIntEnv(\n process.env['OTTO_SESSION_RESUME_WINDOW_MESSAGES'],\n 5_000,\n)\n\n/**\n * RFC-324 D1/R5:turn-gated 压缩的超时兜底(毫秒,默认 30s,G1 已 grill 确认)。\n *\n * 逃生阀压缩 pending 时,下一回合 prompt 前会先 await 其完成;超过本值仍未完成则降级为\n * fire-and-forget 继续发 prompt——**不允许压缩未完成就永久阻塞 turn**(R5 硬约束)。\n *\n * 取值权衡:30s 覆盖正常 LLM 压缩(2-5s)+ 重试余量,超时基本等价于 LLM 故障;\n * 调小会把正常压缩误判为超时,调大则用户在 LLM 故障时等待更久。\n */\nexport const SESSION_COMPACTION_TIMEOUT_MS = parsePositiveIntEnv(\n process.env['OTTO_SESSION_COMPACTION_TIMEOUT_MS'],\n 30_000,\n)\n\n/**\n * RFC-323:进程级驻留总预算(估算口径)。\n *\n * 单会话的**有效**字节预算不再是一个固定值,而是 `clamp(TOTAL / N, MIN, MAX)`——\n * 独占时可用满 MAX,并发时自动收紧,总量始终有界。\n *\n * **1024MB 的算术依据**(CJK 最坏比值 2.05,真实上界 = 估算 × 2.05):\n *\n * | TOTAL | 真实上界 | +基线 1500MB | vs 4096MB 硬顶 |\n * |-------|---------|-------------|--------------|\n * | 1024MB | 2099MB | 3599MB | ✅ 留 ~500MB |\n * | 1280MB | 2624MB | 4124MB | ❌ 超顶 |\n *\n * 取 1024MB:极端情形(所有会话同时贴满预算)下仍留 ~500MB 余量。\n * 基线 1500MB 是 RFC-178 实测值(healthy 时 heap 已 1.5GB/4.1GB)。\n */\nexport const SESSION_TOTAL_RESIDENCY_BUDGET = parsePositiveIntEnv(\n process.env['OTTO_SESSION_TOTAL_RESIDENCY_BUDGET'],\n 1024 * 1024 * 1024,\n)\n\n/**\n * RFC-323:单会话字节预算下界(N 极大时不被摊薄到无法工作)。\n *\n * 低于此值会话会过于频繁触发压缩(每几十条消息就压一次),影响可用性。\n * `SESSION_MAX(50) × MIN(16MB) = 800MB < TOTAL(1024MB)`,故实际不可达。\n */\nexport const SESSION_MIN_PER_SESSION_BYTES = parsePositiveIntEnv(\n process.env['OTTO_SESSION_MIN_PER_SESSION_BYTES'],\n 16 * 1024 * 1024,\n)\n\n/**\n * RFC-323:单会话字节预算上界(N=1 时的封顶)。\n *\n * **2026-08-12 由 512MB 上调至 1024MB(= TOTAL)**:MAX = TOTAL 意味着单会话独占时\n * 可吃满整个进程级预算池(N=1 时 TOTAL/N=1024MB 此前被 MAX 截断)。N>1 时 TOTAL/N\n * 自然 < MAX,MAX 不生效——安全性等价于现有 TOTAL 的设计(非新增风险)。\n *\n * 安全依据(沿用 RFC-323 对 TOTAL=1024MB 的已验证算术,CJK 真实/估算 = 2.05):\n * 1024MB 估算 → 真实约 2099MB + 进程基线约 1500MB ≈ 3599MB,对 4096MB 堆硬钉\n * (`packages/cli/bin/otto.js` 的 `--max-old-space-size`)留约 497MB 余量。\n *\n * 前置条件已兑现:RFC-321 **M6 已落地**(`compaction.ts` 的窗口预检 + map-reduce\n * 分批摘要,`MEMORY_COMPACTION_INPUT_WINDOW_FRACTION=0.6`)——单次 `summarize()` 输入\n * 被机制性钳制在窗口内,**会话体积不再能撑爆压缩调用**,底线2 从\"靠预算参数保证\"\n * 升级为\"靠机制保证\"。此前保守取值(替压缩承担安全余量)已不再必要。\n *\n * **注意本值只是 clamp 的封顶,不是实得预算**:单会话实得 =\n * `clamp(TOTAL / N, MIN, MAX)`(见 `global-residency-engine.ts` 的 `decide`),\n * N 是**同一进程内**的活跃会话数(`countActiveSessionsForAllocation`,跨 otto 进程\n * 互不分摊——每个进程各有独立的 TOTAL 与独立的堆)。MAX=TOTAL 时只在 N=1 独占生效;\n * 多会话并发时仍由 TOTAL/N 摊薄,并有 `ResidencyGovernor` 的内存压力分级\n * (warning 1/2、critical 1/4)兜底。\n *\n * coverage 权衡:M6 分批路径下更大的会话体积意味着更多分段、段摘要再归约,摘要\n * 覆盖率随之下降——这是有意接受的取舍(用一定的摘要精度换取更长的原始历史驻留)。\n */\nexport const SESSION_MAX_PER_SESSION_BYTES = parsePositiveIntEnv(\n process.env['OTTO_SESSION_MAX_PER_SESSION_BYTES'],\n 1024 * 1024 * 1024,\n)\n\n/**\n * RFC-323 M4:驻留预算的运行时配置对象。\n *\n * 存在理由(D6b):上方常量在模块加载时立即求值为 number(env 快照),无法反映\n * app 启动后才 load 的 settings.json。故运行时读值点改从本对象读——由 app 层合并\n * `env(上方常量)> settings > 默认` 后注入。所有字段可选,缺省回退对应常量。\n */\nexport interface ResidencyBudgetConfig {\n totalBytes?: number\n minPerSessionBytes?: number\n maxPerSessionBytes?: number\n maxContentBytes?: number\n maxHistoryMessages?: number\n resumeWindowMessages?: number\n /**\n * RFC-324 D1/R5:turn-gated 压缩的超时兜底(毫秒)。逃生阀压缩超过此值仍未完成时,\n * 降级为 fire-and-forget——**不允许压缩未完成就永久阻塞 turn**。\n */\n compactionTimeoutMs?: number\n}\n\n/**\n * RFC-323 M4:合并 settings 覆盖到 env/默认常量之上,产出完整的 ResidencyBudgetConfig。\n *\n * 优先级:**env(上方常量,已含 env 覆盖)> settings > 默认**。\n * 实现:常量本身已是 `parsePositiveIntEnv(env, 默认)` 的结果——若用户设了 env,常量即为 env 值;\n * 否则为默认值。settings 只在\"用户**没设 env**\"时生效——但模块层无法区分\"常量是 env 值\n * 还是默认值\"。故约定:**settings 值优先于常量默认,但 env 显式设置时由调用方保证不传\n * settings**(见 app 层 `resolveResidencySettingsOverride`:仅当对应 env 未设时才取 settings)。\n */\nexport function resolveResidencyBudget(\n settings?: ResidencyBudgetConfig,\n): Required<ResidencyBudgetConfig> {\n return {\n totalBytes: settings?.totalBytes ?? SESSION_TOTAL_RESIDENCY_BUDGET,\n minPerSessionBytes: settings?.minPerSessionBytes ?? SESSION_MIN_PER_SESSION_BYTES,\n maxPerSessionBytes: settings?.maxPerSessionBytes ?? SESSION_MAX_PER_SESSION_BYTES,\n maxContentBytes: settings?.maxContentBytes ?? SESSION_MAX_CONTENT_BYTES,\n maxHistoryMessages: settings?.maxHistoryMessages ?? SESSION_MAX_HISTORY_MESSAGES,\n resumeWindowMessages: settings?.resumeWindowMessages ?? SESSION_RESUME_WINDOW_MESSAGES,\n compactionTimeoutMs: settings?.compactionTimeoutMs ?? SESSION_COMPACTION_TIMEOUT_MS,\n }\n}\n","/**\n * pulse-survey-trigger.ts — RFC-208 §2.1/§3.1:满意度脉冲调查触发判定纯函数。\n * RFC-209 M3:从 packages/cli 下沉至此(cli 与 service 均已依赖 @x-otto/session-contract,\n * 而 service 不应依赖 cli——EventBridge 需要复用本函数做 web-ui 侧 `pulse-survey.show`\n * 触发判定,见 RFC-209 milestone 执行阶段 grill 确认)。\n *\n * 纯逻辑类,不依赖 @x-otto/tui/@x-otto/coding 类型——判定「本次 prompt.end 是否应展示脉冲调查」,\n * 实际展示(tui.setPulseSurvey / web-ui pulse-survey.show)与数据写入(FeedbackRegistry)\n * 留在调用方(cli 侧 interactive-events.ts / service 侧 event-bridge.ts)。\n *\n * 触发锚点是 prompt.end(对话轮次真正结束的权威时点),按可配置概率随机抽样而非固定周期——\n * 固定周期容易被用户学习产生\"来了、又是这个\"的疲劳感;抽样配合最小回合间隔更接近\"偶尔冒出,\n * 不成为负担\"的调性。判定逻辑必须是纯函数、接受注入的 `random` 参数(RFC-208 重要事项规则 5)\n * ——不得在函数内部直接硬编码调用 `Math.random()`,保证可测试性(CLI 交互层直接用 Math.random\n * 有先例,见 draft-entries.ts,但触发判定这类需要精确验证边界值的逻辑必须可注入固定值测试)。\n *\n * `lastShownTurn` 是进程内存态,不持久化跨会话——重启 otto 后重新从零计间隔,符合\"轻量抽样,\n * 不需要跨会话精确统计\"的调性,避免为此引入额外的持久化状态文件。\n */\n\nexport interface PulseSurveyTriggerState {\n lastShownTurn?: number\n}\n\nexport interface PulseSurveyTriggerConfig {\n enabled: boolean\n probability: number\n minTurnGap: number\n /**\n * 当前是否有 Band A hard modal(如 forcedUpgrade)在场——为真时恒不触发(RFC-208 §5\n * 风险段\"forced-upgrade 并发\"缓解措施之一)。调用方传入 `modals.forcedUpgrade` 等值。\n */\n forcedUpgradeActive: boolean\n}\n\n/**\n * 判定本次 `prompt.end` 是否应展示满意度脉冲调查。\n *\n * @param currentTurn 当前对话轮次(`projState.currentTurn`)\n * @param config 触发配置(来自 `.otto/config.json` 的 `pulse_survey` 块 + 当前 Band A 状态)\n * @param state 触发状态(`lastShownTurn` 进程内存态,调用方持有并在命中时更新)\n * @param random 随机数源,默认 `Math.random`;测试注入固定值验证确定性\n */\nexport function shouldShowPulseSurvey(\n currentTurn: number,\n config: PulseSurveyTriggerConfig,\n state: PulseSurveyTriggerState,\n random: () => number = Math.random,\n): boolean {\n if (!config.enabled) return false\n if (config.forcedUpgradeActive) return false\n if (state.lastShownTurn !== undefined && currentTurn - state.lastShownTurn < config.minTurnGap) return false\n return random() < config.probability\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-otto/session-contract",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.0.1-alpha.3",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -19,8 +19,7 @@
19
19
  "tag": "alpha"
20
20
  },
21
21
  "dependencies": {
22
- "@x-otto/env": "0.1.0-alpha.6",
23
- "@x-otto/interchange": "0.1.0-alpha.3"
22
+ "@x-otto/interchange": "0.1.0-alpha.5"
24
23
  },
25
24
  "private": false,
26
25
  "scripts": {