@roll-agent/core 0.14.0 → 0.14.1

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.
@@ -1 +1 @@
1
- import{randomUUID as t}from"node:crypto";import{createElement as i,useState as o}from"react";import{Box as n,useInput as e}from"ink";import{useSession as s}from"./use-session.js";import{HistoryItemView as m}from"./history-item.js";import{LiveRegion as r}from"./live-region.js";import{StatusLine as a}from"./status-line.js";import{TextPrompt as f}from"./text-prompt.js";import{ConfirmSelect as l}from"./confirm-select.js";import{SlashPopup as p}from"./slash-popup.js";import{filterCommands as d,SLASH_COMMANDS as h}from"./commands.js";import{cycleThinking as c}from"./thinking.js";function u(){return h.map(t=>`${t.name} — ${t.description}`).join("\n")}export function ChatApp(g){const{session:k,model:v,contextWindow:x,onUserSubmit:C,onExit:j}=g,{state:y,submit:L,compact:M,resolveConfirm:T,setDraft:A,setThinking:b,setAutoMode:w,toggleAutoMode:S,commitHistory:D}=s(k,{model:v,contextWindow:x,...g.initialHistory?{initialHistory:g.initialHistory}:{},...g.initialThinkingLevel?{initialThinkingLevel:g.initialThinkingLevel}:{},...g.onThinkingChange?{onThinkingChange:g.onThinkingChange}:{}}),[H,$]=o(0),W="idle"===y.phase&&y.draft.startsWith("/"),E=W?d(y.draft):[],R=Math.max(E.length-1,0),U=Math.min(H,R);e((t,i)=>{i.tab&&i.shift?S():i.meta&&"."===t?b(c(y.status.thinkingLevel,1)):i.meta&&","===t&&b(c(y.status.thinkingLevel,-1))});const q="confirm"===y.phase&&void 0!==y.pendingConfirm?i(l,{prompt:y.pendingConfirm.prompt,args:y.pendingConfirm.args,onDecide:T}):i(f,{value:y.draft,disabled:"idle"!==y.phase,slashActive:W,autoApprove:y.status.autoApprove,onChange:A,onSubmit:t=>{const i=t.trim();0!==i.length?(C(i),L(i)):A("")},onSlashMove:t=>{$(i=>Math.min(Math.max(Math.min(i,R)+t,0),R))},onSlashComplete:()=>{const t=E[U];t&&(A(`${t.name} `),$(0))},onSlashRun:()=>{const i=y.draft.trim().split(/\s+/,1)[0]??"";(i=>{A("");const o=i.trim().split(/\s+/),n=o[0]??"",e=(o[1]??"").toLowerCase(),s=y.status.thinkingLevel;"/compact"!==n?"/think"!==n?"/effort"!==n?"/auto"!==n?"/help"!==n?"/exit"!==n?D({kind:"notice",id:t(),text:`未知命令 ${n}`}):j():D({kind:"notice",id:t(),text:u()}):"on"===e?w(!0):"off"===e?w(!1):S():"low"===e||"medium"===e||"high"===e?b(e):D({kind:"notice",id:t(),text:"用法: /effort low | medium | high"}):b("off"===e?"off":"on"===e?"off"===s?"medium":s:"off"===s?"medium":"off"):M()})(h.some(t=>t.name===i)?y.draft:E[U]?.name??y.draft)}});return i(n,{flexDirection:"column"},i(n,{flexDirection:"column"},...y.history.map(t=>{const o="user"===t.kind||"assistant"===t.kind,e="tool"===t.kind||"denied"===t.kind;return i(n,{key:t.id,marginTop:o?1:0,marginLeft:e?2:0},i(m,{item:t}))})),i(r,{live:y.live}),i(a,{status:y.status}),W?i(p,{matches:E,selected:U}):null,q)}
1
+ import{randomUUID as t}from"node:crypto";import{createElement as i,useMemo as n,useState as o}from"react";import{Box as e,Static as s,useInput as m}from"ink";import{useSession as r}from"./use-session.js";import{HistoryItemView as a}from"./history-item.js";import{LiveRegion as f}from"./live-region.js";import{StatusLine as l}from"./status-line.js";import{TextPrompt as h}from"./text-prompt.js";import{ConfirmSelect as p}from"./confirm-select.js";import{SlashPopup as d}from"./slash-popup.js";import{filterCommands as c,SLASH_COMMANDS as u}from"./commands.js";import{cycleThinking as g}from"./thinking.js";function k(){return u.map(t=>`${t.name} — ${t.description}`).join("\n")}export function ChatApp(v){const{session:x,model:C,contextWindow:j,onUserSubmit:y,onExit:L}=v,{state:M,submit:T,compact:A,resolveConfirm:b,setDraft:w,setThinking:S,setAutoMode:H,toggleAutoMode:$,commitHistory:D}=r(x,{model:C,contextWindow:j,...v.initialHistory?{initialHistory:v.initialHistory}:{},...v.initialThinkingLevel?{initialThinkingLevel:v.initialThinkingLevel}:{},...v.onThinkingChange?{onThinkingChange:v.onThinkingChange}:{}}),W=n(()=>[...M.history],[M.history]),[E,R]=o(0),U="idle"===M.phase&&M.draft.startsWith("/"),q=U?c(M.draft):[],z=Math.max(q.length-1,0),B=Math.min(E,z);m((t,i)=>{i.tab&&i.shift?$():i.meta&&"."===t?S(g(M.status.thinkingLevel,1)):i.meta&&","===t&&S(g(M.status.thinkingLevel,-1))});const F="confirm"===M.phase&&void 0!==M.pendingConfirm?i(p,{prompt:M.pendingConfirm.prompt,args:M.pendingConfirm.args,onDecide:b}):i(h,{value:M.draft,disabled:"idle"!==M.phase,slashActive:U,autoApprove:M.status.autoApprove,onChange:w,onSubmit:t=>{const i=t.trim();0!==i.length?(y(i),T(i)):w("")},onSlashMove:t=>{R(i=>Math.min(Math.max(Math.min(i,z)+t,0),z))},onSlashComplete:()=>{const t=q[B];t&&(w(`${t.name} `),R(0))},onSlashRun:()=>{const i=M.draft.trim().split(/\s+/,1)[0]??"";(i=>{w("");const n=i.trim().split(/\s+/),o=n[0]??"",e=(n[1]??"").toLowerCase(),s=M.status.thinkingLevel;"/compact"!==o?"/think"!==o?"/effort"!==o?"/auto"!==o?"/help"!==o?"/exit"!==o?D({kind:"notice",id:t(),text:`未知命令 ${o}`}):L():D({kind:"notice",id:t(),text:k()}):"on"===e?H(!0):"off"===e?H(!1):$():"low"===e||"medium"===e||"high"===e?S(e):D({kind:"notice",id:t(),text:"用法: /effort low | medium | high"}):S("off"===e?"off":"on"===e?"off"===s?"medium":s:"off"===s?"medium":"off"):A()})(u.some(t=>t.name===i)?M.draft:q[B]?.name??M.draft)}});return i(e,{flexDirection:"column"},i(s,{items:W,children:t=>{const n="user"===t.kind||"assistant"===t.kind,o="tool"===t.kind||"denied"===t.kind;return i(e,{key:t.id,marginTop:n?1:0,marginLeft:o?3:1},i(a,{item:t}))}}),i(e,{marginLeft:1},i(f,{live:M.live})),i(l,{status:M.status}),U?i(d,{matches:q,selected:B}):null,F)}
@@ -1 +1 @@
1
- import{createElement as o,useState as r}from"react";import{Box as e,Text as n,useInput as t,useStdout as i}from"ink";export function ConfirmSelect({prompt:l,args:c,onDecide:s}){const[d,u]=r("no"),{stdout:m}=i(),f=m.columns??80;t((o,r)=>{if(r.leftArrow||r.rightArrow||r.upArrow||r.downArrow)return void u(o=>"yes"===o?"no":"yes");if(r.return||o.includes("\r")||o.includes("\n"))return void s("yes"===d);const e=o.toLowerCase();r.escape||"n"===e?s(!1):"y"===e&&s(!0)});const a=c.length>0&&"{}"!==c;return o(e,{flexDirection:"column",width:f},o(e,{flexDirection:"column",borderStyle:"round",borderColor:"yellow",paddingX:1},o(n,null,l),a?o(n,{dimColor:!0},c):null,o(e,{marginTop:1},o(n,"yes"===d?{color:"green"}:{},("yes"===d?"❯ ":" ")+"Yes"),o(n,"no"===d?{color:"green"}:{},` ${"no"===d?"❯ ":" "}No`))),o(n,{dimColor:!0},"←→/y/n 选择 · Enter 确认 · Esc 取消 · Shift+Tab 自动批准本次及后续"))}
1
+ import{createElement as o,useState as r}from"react";import{Box as e,Text as n,useInput as t,useStdout as i}from"ink";export function ConfirmSelect({prompt:l,args:c,onDecide:s}){const[d,u]=r("no"),{stdout:m}=i(),f=m.columns||80;t((o,r)=>{if(r.leftArrow||r.rightArrow||r.upArrow||r.downArrow)return void u(o=>"yes"===o?"no":"yes");if(r.return||o.includes("\r")||o.includes("\n"))return void s("yes"===d);const e=o.toLowerCase();r.escape||"n"===e?s(!1):"y"===e&&s(!0)});const a=c.length>0&&"{}"!==c;return o(e,{flexDirection:"column",width:f},o(e,{flexDirection:"column",borderStyle:"round",borderColor:"yellow",paddingX:2},o(n,null,l),a?o(n,{dimColor:!0},c):null,o(e,{marginTop:1},o(n,"yes"===d?{color:"green"}:{},("yes"===d?"❯ ":" ")+"Yes"),o(n,"no"===d?{color:"green"}:{},` ${"no"===d?"❯ ":" "}No`))),o(e,{marginLeft:1},o(n,{dimColor:!0},"←→/y/n 选择 · Enter 确认 · Esc 取消 · Shift+Tab 自动批准本次及后续")))}
@@ -1 +1 @@
1
- import{SUMMARY_ACK as t,SUMMARY_PREFIX as o}from"@roll-agent/runtime";import{formatToolInput as n}from"../../utils/tool-format.js";const e=new Set(["error-text","error-json","execution-denied"]);function r(t){return"string"==typeof t?t:t.map(t=>"text"===t.type?t.text:"").join("")}function s(t){const o=t.indexOf("__");return o>=0?`${t.slice(0,o)}.${t.slice(o+2)}`:t}export function messagesToHistory(i,c="h"){const l=new Map;for(const t of i)if("tool"===t.role&&"string"!=typeof t.content)for(const o of t.content)if("tool-result"===o.type){const t=o.output.type;l.set(o.toolCallId,!e.has(t))}const a=[];return i.forEach((e,i)=>{const f=`${c}-${String(i)}`;if("user"===e.role){const t=r(e.content);return t.startsWith(o)?void a.push({kind:"compaction",id:f,notice:"🗜 已恢复的上下文摘要"}):void(t.length>0&&a.push({kind:"user",id:f,text:t}))}if("assistant"===e.role){const o=r(e.content);if(o.startsWith(t))return;o.length>0&&a.push({kind:"assistant",id:f,text:o}),"string"!=typeof e.content&&e.content.forEach((t,o)=>{"tool-call"===t.type&&a.push({kind:"tool",id:`${f}-${String(o)}`,name:s(t.toolName),args:n(t.input),ok:l.get(t.toolCallId)??!0})})}}),a}
1
+ import{SUMMARY_ACK as t,SUMMARY_PREFIX as o}from"@roll-agent/runtime";import{formatToolInput as n}from"../../utils/tool-format.js";import{GLYPHS as e}from"../../utils/glyphs.js";const r=new Set(["error-text","error-json","execution-denied"]);function s(t){return"string"==typeof t?t:t.map(t=>"text"===t.type?t.text:"").join("")}function i(t){const o=t.indexOf("__");return o>=0?`${t.slice(0,o)}.${t.slice(o+2)}`:t}export function messagesToHistory(c,l="h"){const a=new Map;for(const t of c)if("tool"===t.role&&"string"!=typeof t.content)for(const o of t.content)if("tool-result"===o.type){const t=o.output.type;a.set(o.toolCallId,!r.has(t))}const f=[];return c.forEach((r,c)=>{const p=`${l}-${String(c)}`;if("user"===r.role){const t=s(r.content);return t.startsWith(o)?void f.push({kind:"compaction",id:p,notice:`${e.compact} 已恢复的上下文摘要`}):void(t.length>0&&f.push({kind:"user",id:p,text:t}))}if("assistant"===r.role){const o=s(r.content);if(o.startsWith(t))return;o.length>0&&f.push({kind:"assistant",id:p,text:o}),"string"!=typeof r.content&&r.content.forEach((t,o)=>{"tool-call"===t.type&&f.push({kind:"tool",id:`${p}-${String(o)}`,name:i(t.toolName),args:n(t.input),ok:a.get(t.toolCallId)??!0})})}}),f}
@@ -1 +1 @@
1
- import{createElement as n}from"react";import{Box as l,Text as t}from"ink";import{Spinner as e}from"./spinner.js";import{ThinkingText as o}from"./thinking-text.js";import{ToolLabel as i}from"./tool-label.js";export function LiveRegion({live:r}){return n(l,{flexDirection:"column"},r.streamingText.length>0?n(o,{text:r.thinkTagOpen?`<think>${r.streamingText}`:r.streamingText}):null,r.thinking?n(l,{marginTop:1},n(e,null),n(t,{dimColor:!0}," 思考中…")):null,...r.activeTools.map(o=>n(l,{key:o.toolCallId},n(e,null),n(t,null," "),n(i,{name:o.name}),o.args.length>0?n(t,{dimColor:!0},` ${o.args}`):null)),r.compacting?n(l,null,n(e,null),n(t,{dimColor:!0}," 压缩上下文中…")):null)}
1
+ import{createElement as n}from"react";import{Box as l,Text as t}from"ink";import{Spinner as e}from"./spinner.js";import{ThinkingText as i}from"./thinking-text.js";import{ToolLabel as o}from"./tool-label.js";export function LiveRegion({live:r}){return n(l,{flexDirection:"column"},r.streamingText.length>0?n(l,{marginTop:1},n(i,{text:r.thinkTagOpen?`<think>${r.streamingText}`:r.streamingText})):null,r.thinking?n(l,{marginTop:1},n(e,null),n(t,{dimColor:!0}," 思考中…")):null,...r.activeTools.map(i=>n(l,{key:i.toolCallId,marginLeft:2},n(e,null),n(t,null," "),n(o,{name:i.name}),i.args.length>0?n(t,{dimColor:!0},` ${i.args}`):null)),r.compacting?n(l,null,n(e,null),n(t,{dimColor:!0}," 压缩上下文中…")):null)}
@@ -1 +1 @@
1
- import{formatToolInput as t}from"../../utils/tool-format.js";import{endsInsideThink as e}from"./thinking-text.js";const i={streamingText:"",thinking:!1,thinkTagOpen:!1,activeTools:[],compacting:!1,producedOutput:!1};function n(t,e){return e?`<think>${t}`:t}export function createInitialState(t,e,n){return{history:n?.history??[],draft:"",live:i,status:{model:t,contextWindow:e,turnUsage:void 0,sessionUsage:void 0,contextInputTokens:void 0,outputTokensPerSecond:void 0,thinkingLevel:n?.thinkingLevel??"medium",autoApprove:!1},phase:"idle",pendingConfirm:void 0}}export function buildConfirmPrompt(t){const e=t.reason?`(${t.reason})`:"";return`执行 ${t.agentName}.${t.toolName}${e}?`}function o(t){const e="auto"===t.reason?"自动压缩":"手动压缩",i=t.truncatedTools?`,精简 ${String(t.truncatedTools)} 个工具结果`:"";return 0!==t.removed||t.truncatedTools?`🗜 ${e}(${t.strategy}):移除 ${String(t.removed)} 条 → 保留 ${String(t.kept)} 条${i}`:`🗜 ${e}:无需压缩`}const r=[["已取消执行","已取消"],["策略拒绝执行","策略拒绝"]];function s(t){return"string"==typeof t?t:"object"==typeof t&&null!==t&&"output"in t&&"string"==typeof t.output?t.output:void 0}export function denialLabel(t){const e=s(t);if(void 0!==e)return r.find(([t])=>e.startsWith(t))?.[1]}function a(t,e,i){const n=t.live.activeTools.find(t=>t.toolCallId===i.toolCallId),o=n?.name??`${i.agentName}.${i.toolName}`,r=n?.args??"",s=i.isError?denialLabel(i.output):void 0,a=void 0!==s?{kind:"denied",id:e,name:o,label:s}:{kind:"tool",id:e,name:o,args:r,ok:!i.isError};return{...t,history:[...t.history,a],live:{...t.live,activeTools:t.live.activeTools.filter(t=>t.toolCallId!==i.toolCallId)}}}function u(r,s,u){switch(u.type){case"message-start":return{...r,live:{...r.live,thinking:!0}};case"text-delta":return{...r,live:{...r.live,thinking:!1,producedOutput:!0,streamingText:r.live.streamingText+u.delta}};case"tool-call":{const i=r.live.streamingText.length>0?[{kind:"assistant",id:s,text:n(r.live.streamingText,r.live.thinkTagOpen)}]:[];return{...r,history:[...r.history,...i],live:{...r.live,thinking:!1,producedOutput:!0,streamingText:"",thinkTagOpen:e(r.live.streamingText,r.live.thinkTagOpen),activeTools:[...r.live.activeTools,{toolCallId:u.toolCallId,name:`${u.agentName}.${u.toolName}`,args:t(u.input)}]}}}case"tool-result":return a(r,s,u);case"confirmation-required":return{...r,phase:"confirm",pendingConfirm:{approvalId:u.approvalId,prompt:buildConfirmPrompt(u),args:t(u.input)}};case"compaction-start":return{...r,live:{...r.live,compacting:!0}};case"context-compacted":return{...r,live:{...r.live,compacting:!1},history:[...r.history,{kind:"compaction",id:s,notice:o(u)}]};case"message-finish":{const t=[];return r.live.streamingText.length>0?t.push({kind:"assistant",id:s,text:n(r.live.streamingText,r.live.thinkTagOpen)}):!r.live.producedOutput&&(u.totalUsage?.outputTokens??0)>0&&t.push({kind:"notice",id:s,text:"模型本轮只返回了 thinking/reasoning,没有生成可见回复"}),u.stoppedAtStepLimit&&t.push({kind:"notice",id:`${s}-step-limit`,text:"已达单轮最大工具步数,任务可能未完成 — 继续追问即可接着做,或调高 runtime.max-steps"}),{...r,history:[...r.history,...t],live:{...i},status:{...r.status,turnUsage:u.totalUsage,sessionUsage:u.sessionUsage,contextInputTokens:u.contextInputTokens,outputTokensPerSecond:u.outputTokensPerSecond}}}case"error":return{...r,history:[...r.history,{kind:"error",id:s,message:u.message}],live:{...i}};default:return r}}export function chatReducer(t,e){switch(e.type){case"submit-user":return{...t,history:[...t.history,{kind:"user",id:e.id,text:e.text}],draft:"",live:{...i},phase:"busy",pendingConfirm:void 0};case"set-draft":return{...t,draft:e.value};case"set-thinking":return{...t,status:{...t.status,thinkingLevel:e.level}};case"set-auto":return{...t,status:{...t.status,autoApprove:e.value}};case"commit-history":return{...t,history:[...t.history,e.item],draft:""};case"start-compaction":return{...t,live:{...i},phase:"busy",pendingConfirm:void 0};case"session-event":return u(t,e.id,e.event);case"confirm-resolved":return{...t,phase:"busy",pendingConfirm:void 0};case"turn-end":return{...t,phase:"idle",live:{...i}};default:return t}}
1
+ import{formatToolInput as t}from"../../utils/tool-format.js";import{GLYPHS as e}from"../../utils/glyphs.js";import{endsInsideThink as i}from"./thinking-text.js";const n={streamingText:"",thinking:!1,thinkTagOpen:!1,activeTools:[],compacting:!1,producedOutput:!1};function o(t,e){return e?`<think>${t}`:t}export function createInitialState(t,e,i){return{history:i?.history??[],draft:"",live:n,status:{model:t,contextWindow:e,turnUsage:void 0,sessionUsage:void 0,contextInputTokens:void 0,outputTokensPerSecond:void 0,thinkingLevel:i?.thinkingLevel??"medium",autoApprove:!1},phase:"idle",pendingConfirm:void 0}}export function buildConfirmPrompt(t){const e=t.reason?`(${t.reason})`:"";return`执行 ${t.agentName}.${t.toolName}${e}?`}function r(t){const i="auto"===t.reason?"自动压缩":"手动压缩",n=t.truncatedTools?`,精简 ${String(t.truncatedTools)} 个工具结果`:"";return 0!==t.removed||t.truncatedTools?`${e.compact} ${i}(${t.strategy}):移除 ${String(t.removed)} 条 → 保留 ${String(t.kept)} 条${n}`:`${e.compact} ${i}:无需压缩`}const s=[["已取消执行","已取消"],["策略拒绝执行","策略拒绝"]];function a(t){return"string"==typeof t?t:"object"==typeof t&&null!==t&&"output"in t&&"string"==typeof t.output?t.output:void 0}export function denialLabel(t){const e=a(t);if(void 0!==e)return s.find(([t])=>e.startsWith(t))?.[1]}function u(t,e,i){const n=t.live.activeTools.find(t=>t.toolCallId===i.toolCallId),o=n?.name??`${i.agentName}.${i.toolName}`,r=n?.args??"",s=i.isError?denialLabel(i.output):void 0,a=void 0!==s?{kind:"denied",id:e,name:o,label:s}:{kind:"tool",id:e,name:o,args:r,ok:!i.isError};return{...t,history:[...t.history,a],live:{...t.live,activeTools:t.live.activeTools.filter(t=>t.toolCallId!==i.toolCallId)}}}function l(e,s,a){switch(a.type){case"message-start":return{...e,live:{...e.live,thinking:!0}};case"text-delta":return{...e,live:{...e.live,thinking:!1,producedOutput:!0,streamingText:e.live.streamingText+a.delta}};case"tool-call":{const n=e.live.streamingText.length>0?[{kind:"assistant",id:s,text:o(e.live.streamingText,e.live.thinkTagOpen)}]:[];return{...e,history:[...e.history,...n],live:{...e.live,thinking:!1,producedOutput:!0,streamingText:"",thinkTagOpen:i(e.live.streamingText,e.live.thinkTagOpen),activeTools:[...e.live.activeTools,{toolCallId:a.toolCallId,name:`${a.agentName}.${a.toolName}`,args:t(a.input)}]}}}case"tool-result":return u(e,s,a);case"confirmation-required":return{...e,phase:"confirm",pendingConfirm:{approvalId:a.approvalId,prompt:buildConfirmPrompt(a),args:t(a.input)}};case"compaction-start":return{...e,live:{...e.live,compacting:!0}};case"context-compacted":return{...e,live:{...e.live,compacting:!1},history:[...e.history,{kind:"compaction",id:s,notice:r(a)}]};case"message-finish":{const t=[];return e.live.streamingText.length>0?t.push({kind:"assistant",id:s,text:o(e.live.streamingText,e.live.thinkTagOpen)}):!e.live.producedOutput&&(a.totalUsage?.outputTokens??0)>0&&t.push({kind:"notice",id:s,text:"模型本轮只返回了 thinking/reasoning,没有生成可见回复"}),a.stoppedAtStepLimit&&t.push({kind:"notice",id:`${s}-step-limit`,text:"已达单轮最大工具步数,任务可能未完成 — 继续追问即可接着做,或调高 runtime.max-steps"}),{...e,history:[...e.history,...t],live:{...n},status:{...e.status,turnUsage:a.totalUsage,sessionUsage:a.sessionUsage,contextInputTokens:a.contextInputTokens,outputTokensPerSecond:a.outputTokensPerSecond}}}case"error":return{...e,history:[...e.history,{kind:"error",id:s,message:a.message}],live:{...n}};default:return e}}export function chatReducer(t,e){switch(e.type){case"submit-user":return{...t,history:[...t.history,{kind:"user",id:e.id,text:e.text}],draft:"",live:{...n},phase:"busy",pendingConfirm:void 0};case"set-draft":return{...t,draft:e.value};case"set-thinking":return{...t,status:{...t.status,thinkingLevel:e.level}};case"set-auto":return{...t,status:{...t.status,autoApprove:e.value}};case"commit-history":return{...t,history:[...t.history,e.item],draft:""};case"start-compaction":return{...t,live:{...n},phase:"busy",pendingConfirm:void 0};case"session-event":return l(t,e.id,e.event);case"confirm-resolved":return{...t,phase:"busy",pendingConfirm:void 0};case"turn-end":return{...t,phase:"idle",live:{...n}};default:return t}}
@@ -1 +1 @@
1
- import{createElement as o}from"react";import{Box as t,Text as e,useStdout as s}from"ink";import{computeUsageParts as n,contextPressure as p,formatContextUsage as r,formatThroughput as i,formatTokens as c,formatTurnUsage as l}from"../../utils/token-format.js";import{displayWidth as u}from"./markdown.js";import{thinkingLabel as m}from"./thinking.js";const a={ok:{dimColor:!0},warn:{color:"yellow"},critical:{color:"red"}},k={off:"off",low:"low",medium:"med",high:"high"},d=["tps","session","turn","think"],f=" · ";export function composeStatusSegments(o,t){const e=n(o.turnUsage,o.sessionUsage,o.contextWindow,o.contextInputTokens),s=[{key:"model",full:o.model,compact:o.model,props:{color:"magenta"}},{key:"think",full:m(o.thinkingLevel),compact:`🧠 ${k[o.thinkingLevel]}`,props:"off"===o.thinkingLevel?{color:"yellow"}:{dimColor:!0}}];o.autoApprove&&s.push({key:"auto",full:"⏵⏵ auto-approve",compact:"⏵⏵ auto",props:{color:"yellow"}});const h=r(e);void 0!==h&&void 0!==e.usedTokens&&void 0!==e.contextWindow&&s.push({key:"ctx",full:h,compact:`ctx ${c(e.usedTokens)}/${c(e.contextWindow)}`,props:a[p(e.percentLeft)]});const y=l(e);if(void 0!==y){const o=[];void 0!==e.inputTokens&&o.push(`↑${c(e.inputTokens)}`),void 0!==e.outputTokens&&o.push(`↓${c(e.outputTokens)}`),s.push({key:"turn",full:y,compact:o.join(" "),props:{dimColor:!0}})}const v=i(o.outputTokensPerSecond);void 0!==v&&s.push({key:"tps",full:v,compact:v.replace(" tok/s","t/s"),props:{dimColor:!0}}),void 0!==e.sessionTokens&&s.push({key:"session",full:`session ${c(e.sessionTokens)}`,compact:`Σ${c(e.sessionTokens)}`,props:{dimColor:!0}});const w=(o,t)=>o.map(o=>({key:o.key,text:o[t],props:o.props})),g=o=>u(o.map(o=>o.text).join(f))<=t,x=w(s,"full");if(g(x))return x;let T=s,$=w(T,"compact");for(const o of d){if(g($))break;T=T.filter(t=>t.key!==o),$=w(T,"compact")}return $}export function StatusLine({status:n}){const{stdout:p}=s(),r=p.columns??80,i=composeStatusSegments(n,r);return o(t,{width:r},o(e,{wrap:"truncate-end"},...i.flatMap((t,s)=>[...s>0?[o(e,{key:`${t.key}-sep`,dimColor:!0},f)]:[],o(e,{key:t.key,...t.props},t.text)])))}
1
+ import{createElement as o}from"react";import{Box as t,Text as e,useStdout as s}from"ink";import{computeUsageParts as n,contextPressure as p,formatContextUsage as i,formatThroughput as r,formatTokens as c,formatTurnUsage as l}from"../../utils/token-format.js";import{displayWidth as u}from"./markdown.js";import{GLYPHS as m}from"../../utils/glyphs.js";import{thinkingLabel as a}from"./thinking.js";const k={ok:{dimColor:!0},warn:{color:"yellow"},critical:{color:"red"}},f={off:"off",low:"low",medium:"med",high:"high"},d=["tps","session","turn","think"],h=" · ";export function composeStatusSegments(o,t){const e=n(o.turnUsage,o.sessionUsage,o.contextWindow,o.contextInputTokens),s=[{key:"model",full:o.model,compact:o.model,props:{color:"magenta"}},{key:"think",full:a(o.thinkingLevel),compact:`${m.think} ${f[o.thinkingLevel]}`,props:"off"===o.thinkingLevel?{color:"yellow"}:{dimColor:!0}}];o.autoApprove&&s.push({key:"auto",full:`${m.auto} auto-approve`,compact:`${m.auto} auto`,props:{color:"yellow"}});const y=i(e);void 0!==y&&void 0!==e.usedTokens&&void 0!==e.contextWindow&&s.push({key:"ctx",full:y,compact:`ctx ${c(e.usedTokens)}/${c(e.contextWindow)}`,props:k[p(e.percentLeft)]});const v=l(e);if(void 0!==v){const o=[];void 0!==e.inputTokens&&o.push(`↑${c(e.inputTokens)}`),void 0!==e.outputTokens&&o.push(`↓${c(e.outputTokens)}`),s.push({key:"turn",full:v,compact:o.join(" "),props:{dimColor:!0}})}const g=r(o.outputTokensPerSecond);void 0!==g&&s.push({key:"tps",full:g,compact:g.replace(" tok/s","t/s"),props:{dimColor:!0}}),void 0!==e.sessionTokens&&s.push({key:"session",full:`session ${c(e.sessionTokens)}`,compact:`Σ${c(e.sessionTokens)}`,props:{dimColor:!0}});const w=(o,t)=>o.map(o=>({key:o.key,text:o[t],props:o.props})),x=o=>u(o.map(o=>o.text).join(h))<=t,T=w(s,"full");if(x(T))return T;let $=s,j=w($,"compact");for(const o of d){if(x(j))break;$=$.filter(t=>t.key!==o),j=w($,"compact")}return j}export function StatusLine({status:n}){const{stdout:p}=s(),i=p.columns||80,r=composeStatusSegments(n,i);return o(t,{width:i},o(e,{wrap:"truncate-end"},...r.flatMap((t,s)=>[...s>0?[o(e,{key:`${t.key}-sep`,dimColor:!0},h)]:[],o(e,{key:t.key,...t.props},t.text)])))}
@@ -1 +1 @@
1
- import{createElement as r,useRef as t}from"react";import{Box as e,Text as n,useInput as o,useStdout as i}from"ink";function l(r){return/^\[\?\d+u$/.test(r)||/^\x9b\?\d+u$/.test(r)}export function TextPrompt(u){const{value:c,disabled:a,slashActive:s,autoApprove:d,onChange:f,onSubmit:m}=u,{stdout:h}=i(),p=h.columns??80,v=t(c);v.current=c;const b=r=>{v.current=r,f(r)};o((r,t)=>{if(t.meta&&("."===r||","===r))return;if(l(r))return;if(t.backspace||t.delete)return void b(v.current.slice(0,-1));if("\n"===r||t.ctrl&&"j"===r||t.return&&(t.shift||t.meta))return void b(`${v.current}\n`);if(t.return||r.includes("\r")){if(s)return void u.onSlashRun();const t=r.split("\r",1)[0]??"";return void m(v.current+t)}if(s){if(t.upArrow)return void u.onSlashMove(-1);if(t.downArrow)return void u.onSlashMove(1);if(t.tab&&!t.shift)return void u.onSlashComplete();if(t.escape)return void b("")}t.ctrl||t.escape||t.tab||t.upArrow||t.downArrow||t.leftArrow||t.rightArrow||r.length>0&&b(v.current+r)},{isActive:!a});const S=c.split("\n"),w=r(e,{flexDirection:"column"},...S.map((t,o)=>{const i=o===S.length-1,l=0===o?r(n,{color:"green"},"› "):r(n,null," ");return r(e,{key:String(o)},l,r(n,a?{dimColor:!0}:{},t),i&&!a?r(n,null,"▏"):null)})),A=s?"↑↓ 选择 · Tab 补全 · Enter 执行 · Esc 取消":d?"Shift+Tab 关闭 · Enter 发送 · Shift+Enter/Ctrl+J 换行 · / 命令":"Enter 发送 · Shift+Enter/Ctrl+J 换行 · / 命令 · Shift+Tab 自动批准",g=d?r(e,null,r(n,{color:"yellow"},"⏵⏵ auto"),r(n,{dimColor:!0},` · ${A}`)):r(n,{dimColor:!0},A);return r(e,{flexDirection:"column",width:p},r(e,{borderStyle:"round",borderColor:a?"gray":"cyan",paddingX:1},w),g)}
1
+ import{createElement as r,useRef as t}from"react";import{Box as e,Text as n,useInput as o,useStdout as i}from"ink";import{GLYPHS as l}from"../../utils/glyphs.js";function u(r){return/^\[\?\d+u$/.test(r)||/^\x9b\?\d+u$/.test(r)}export function TextPrompt(c){const{value:s,disabled:a,slashActive:d,autoApprove:f,onChange:m,onSubmit:p}=c,{stdout:h}=i(),v=h.columns||80,b=t(s);b.current=s;const S=r=>{b.current=r,m(r)};o((r,t)=>{if(t.meta&&("."===r||","===r))return;if(u(r))return;if(t.backspace||t.delete)return void S(b.current.slice(0,-1));if("\n"===r||t.ctrl&&"j"===r||t.return&&(t.shift||t.meta))return void S(`${b.current}\n`);if(t.return||r.includes("\r")){if(d)return void c.onSlashRun();const t=r.split("\r",1)[0]??"";return void p(b.current+t)}if(d){if(t.upArrow)return void c.onSlashMove(-1);if(t.downArrow)return void c.onSlashMove(1);if(t.tab&&!t.shift)return void c.onSlashComplete();if(t.escape)return void S("")}t.ctrl||t.escape||t.tab||t.upArrow||t.downArrow||t.leftArrow||t.rightArrow||r.length>0&&S(b.current+r)},{isActive:!a});const g=s.split("\n"),w=r(e,{flexDirection:"column"},...g.map((t,o)=>{const i=o===g.length-1,l=0===o?r(n,{color:"green"},"› "):r(n,null," ");return r(e,{key:String(o)},l,r(n,a?{dimColor:!0}:{},t),i&&!a?r(n,null,"▏"):null)})),A=d?"↑↓ 选择 · Tab 补全 · Enter 执行 · Esc 取消":f?"Shift+Tab 关闭 · Enter 发送 · Shift+Enter/Ctrl+J 换行 · / 命令":"Enter 发送 · Shift+Enter/Ctrl+J 换行 · / 命令 · Shift+Tab 自动批准",C=r(e,{marginLeft:1},...f?[r(n,{color:"yellow"},`${l.auto} auto`),r(n,{dimColor:!0},` · ${A}`)]:[r(n,{dimColor:!0},A)]);return r(e,{flexDirection:"column",width:v},r(e,{borderStyle:"round",borderColor:a?"gray":"cyan",paddingX:2},w),C)}
@@ -1 +1 @@
1
- const n=["off","low","medium","high"];export function cycleThinking(t,i){const e=n.indexOf(t),o=Math.min(Math.max(e+i,0),n.length-1);return n[o]??t}export function thinkingLabel(n){return`🧠 ${n}`}
1
+ import{GLYPHS as n}from"../../utils/glyphs.js";const t=["off","low","medium","high"];export function cycleThinking(n,i){const o=t.indexOf(n),e=Math.min(Math.max(o+i,0),t.length-1);return t[e]??n}export function thinkingLabel(t){return`${n.think} ${t}`}
@@ -1 +1 @@
1
- import s from"chalk";import{isCancel as e,select as t}from"@clack/prompts";import{createSpinner as n,log as i}from"./output.js";import{computeUsageParts as a,formatUsageLine as o}from"./token-format.js";import{formatToolInput as r}from"./tool-format.js";export const clackConfirm=async s=>{const n=await t({message:s,options:[{value:"yes",label:"Yes"},{value:"no",label:"No"}],initialValue:"no"});return!e(n)&&"yes"===n};function p(s){const e=[`chat.${s.stage}`,s.message];return void 0!==s.elapsedMs&&e.push(`${String(s.elapsedMs)}ms`),void 0!==s.data&&e.push(JSON.stringify(s.data)),e.join(" · ")}export class ChatRenderer{confirm;contextWindow;spinners=new Map;compactionSpinner;messageSpinner;streaming=!1;constructor(s,e){this.confirm=s,this.contextWindow=e}async handle(e,t){switch(e.type){case"debug":i.debug(p(e));break;case"message-start":this.startMessageSpinner();break;case"text-delta":this.stopMessageSpinner(),process.stdout.write(e.delta),this.streaming=!0;break;case"tool-call":{this.stopMessageSpinner(),this.flushLine();const t=n(`${s.cyan(`${e.agentName}.${e.toolName}`)} ${s.gray(r(e.input))}`);t.start(),this.spinners.set(e.toolCallId,t);break}case"tool-result":{const s=this.spinners.get(e.toolCallId);s&&(e.isError?s.fail():s.succeed(),this.spinners.delete(e.toolCallId));break}case"confirmation-required":{this.stopMessageSpinner(),this.flushLine();const s=e.reason?`(${e.reason})`:"";await this.confirm(`执行 ${e.agentName}.${e.toolName}${s}?`)?t.approve(e.approvalId):t.reject(e.approvalId,"用户取消");break}case"compaction-start":this.stopMessageSpinner(),this.flushLine(),this.compactionSpinner=n(s.gray("压缩上下文中…")),this.compactionSpinner.start();break;case"context-compacted":{this.stopCompactionSpinner(),this.flushLine();const t="auto"===e.reason?"自动压缩":"手动压缩",n=e.truncatedTools?`,精简 ${String(e.truncatedTools)} 个工具结果`:"",i=0!==e.removed||e.truncatedTools?`🗜 ${t}(${e.strategy}):移除 ${String(e.removed)} 条 → 保留 ${String(e.kept)} 条${n}`:`🗜 ${t}:无需压缩`;process.stderr.write(`${s.gray(i)}\n`);break}case"error":this.stopMessageSpinner(),this.stopCompactionSpinner(),this.flushLine(),i.error(e.message);break;case"message-finish":{this.stopMessageSpinner(),this.flushLine(),0===e.text.length&&(e.totalUsage?.outputTokens??0)>0&&i.warn("模型本轮只返回了 thinking/reasoning,没有生成可见回复"),e.stoppedAtStepLimit&&i.warn("已达单轮最大工具步数,任务可能未完成 — 继续追问即可接着做,或调高 runtime.max-steps");const t=o(a(e.totalUsage,e.sessionUsage,this.contextWindow,e.contextInputTokens));t&&process.stderr.write(`${s.gray(t)}\n`);break}}}stopCompactionSpinner(){this.compactionSpinner&&(this.compactionSpinner.stop(),this.compactionSpinner=void 0)}startMessageSpinner(){this.stopMessageSpinner(),this.messageSpinner=n(s.gray("思考中…")),this.messageSpinner.start()}stopMessageSpinner(){this.messageSpinner&&(this.messageSpinner.stop(),this.messageSpinner=void 0)}flushLine(){this.streaming&&(process.stdout.write("\n"),this.streaming=!1)}}
1
+ import s from"chalk";import{isCancel as e,select as t}from"@clack/prompts";import{createSpinner as n,log as o}from"./output.js";import{GLYPHS as i}from"./glyphs.js";import{computeUsageParts as a,formatUsageLine as r}from"./token-format.js";import{formatToolInput as p}from"./tool-format.js";export const clackConfirm=async s=>{const n=await t({message:s,options:[{value:"yes",label:"Yes"},{value:"no",label:"No"}],initialValue:"no"});return!e(n)&&"yes"===n};function c(s){const e=[`chat.${s.stage}`,s.message];return void 0!==s.elapsedMs&&e.push(`${String(s.elapsedMs)}ms`),void 0!==s.data&&e.push(JSON.stringify(s.data)),e.join(" · ")}export class ChatRenderer{confirm;contextWindow;spinners=new Map;compactionSpinner;messageSpinner;streaming=!1;constructor(s,e){this.confirm=s,this.contextWindow=e}async handle(e,t){switch(e.type){case"debug":o.debug(c(e));break;case"message-start":this.startMessageSpinner();break;case"text-delta":this.stopMessageSpinner(),process.stdout.write(e.delta),this.streaming=!0;break;case"tool-call":{this.stopMessageSpinner(),this.flushLine();const t=n(`${s.cyan(`${e.agentName}.${e.toolName}`)} ${s.gray(p(e.input))}`);t.start(),this.spinners.set(e.toolCallId,t);break}case"tool-result":{const s=this.spinners.get(e.toolCallId);s&&(e.isError?s.fail():s.succeed(),this.spinners.delete(e.toolCallId));break}case"confirmation-required":{this.stopMessageSpinner(),this.flushLine();const s=e.reason?`(${e.reason})`:"";await this.confirm(`执行 ${e.agentName}.${e.toolName}${s}?`)?t.approve(e.approvalId):t.reject(e.approvalId,"用户取消");break}case"compaction-start":this.stopMessageSpinner(),this.flushLine(),this.compactionSpinner=n(s.gray("压缩上下文中…")),this.compactionSpinner.start();break;case"context-compacted":{this.stopCompactionSpinner(),this.flushLine();const t="auto"===e.reason?"自动压缩":"手动压缩",n=e.truncatedTools?`,精简 ${String(e.truncatedTools)} 个工具结果`:"",o=0!==e.removed||e.truncatedTools?`${i.compact} ${t}(${e.strategy}):移除 ${String(e.removed)} 条 → 保留 ${String(e.kept)} 条${n}`:`${i.compact} ${t}:无需压缩`;process.stderr.write(`${s.gray(o)}\n`);break}case"error":this.stopMessageSpinner(),this.stopCompactionSpinner(),this.flushLine(),o.error(e.message);break;case"message-finish":{this.stopMessageSpinner(),this.flushLine(),0===e.text.length&&(e.totalUsage?.outputTokens??0)>0&&o.warn("模型本轮只返回了 thinking/reasoning,没有生成可见回复"),e.stoppedAtStepLimit&&o.warn("已达单轮最大工具步数,任务可能未完成 — 继续追问即可接着做,或调高 runtime.max-steps");const t=r(a(e.totalUsage,e.sessionUsage,this.contextWindow,e.contextInputTokens));t&&process.stderr.write(`${s.gray(t)}\n`);break}}}stopCompactionSpinner(){this.compactionSpinner&&(this.compactionSpinner.stop(),this.compactionSpinner=void 0)}startMessageSpinner(){this.stopMessageSpinner(),this.messageSpinner=n(s.gray("思考中…")),this.messageSpinner.start()}stopMessageSpinner(){this.messageSpinner&&(this.messageSpinner.stop(),this.messageSpinner=void 0)}flushLine(){this.streaming&&(process.stdout.write("\n"),this.streaming=!1)}}
@@ -0,0 +1,9 @@
1
+ export declare const GLYPHS: {
2
+ readonly think: "🧠";
3
+ readonly auto: "⏵⏵";
4
+ readonly compact: "🗜";
5
+ } | {
6
+ readonly think: "think";
7
+ readonly auto: ">>";
8
+ readonly compact: "*";
9
+ };
@@ -0,0 +1 @@
1
+ import t from"is-unicode-supported";const o=t();export const GLYPHS=o?{think:"🧠",auto:"⏵⏵",compact:"🗜"}:{think:"think",auto:">>",compact:"*"};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roll-agent/core",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",