mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-26 01:01:40 +00:00
feat: fix img pasting in new ink plus newline after tools
This commit is contained in:
parent
b04248f4d5
commit
3fd5cf6e3c
8 changed files with 198 additions and 75 deletions
|
|
@ -436,4 +436,3 @@ export const clearYogaNodeReferences = (node: DOMElement | TextNode): void => {
|
|||
|
||||
node.yogaNode = undefined
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
import { clamp } from './layout/geometry.js'
|
||||
import type { Screen, StylePool } from './screen.js'
|
||||
import { CellWidth, cellAt, cellAtIndex, setCellStyleId } from './screen.js'
|
||||
import { cellAt, cellAtIndex, CellWidth, setCellStyleId } from './screen.js'
|
||||
|
||||
type Point = { col: number; row: number }
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,15 @@ import { useCompletion } from './hooks/useCompletion.js'
|
|||
import { useInputHistory } from './hooks/useInputHistory.js'
|
||||
import { useQueue } from './hooks/useQueue.js'
|
||||
import { writeOsc52Clipboard } from './lib/osc52.js'
|
||||
import { buildToolTrailLine, compactPreview, fmtK, hasInterpolation, isToolTrailResultLine, pick, sameToolTrailGroup } from './lib/text.js'
|
||||
import {
|
||||
buildToolTrailLine,
|
||||
compactPreview,
|
||||
fmtK,
|
||||
hasInterpolation,
|
||||
isToolTrailResultLine,
|
||||
pick,
|
||||
sameToolTrailGroup
|
||||
} from './lib/text.js'
|
||||
import { DEFAULT_THEME, fromSkin, type Theme } from './theme.js'
|
||||
import type {
|
||||
ActiveTool,
|
||||
|
|
@ -111,7 +119,9 @@ const toTranscriptMessages = (rows: unknown): Msg[] => {
|
|||
let pendingTools: string[] = []
|
||||
|
||||
for (const row of rows) {
|
||||
if (!row || typeof row !== 'object') continue
|
||||
if (!row || typeof row !== 'object') {
|
||||
continue
|
||||
}
|
||||
|
||||
const role = (row as any).role
|
||||
const text = (row as any).text
|
||||
|
|
@ -120,18 +130,24 @@ const toTranscriptMessages = (rows: unknown): Msg[] => {
|
|||
const name = (row as any).name ?? 'tool'
|
||||
const ctx = (row as any).context ?? ''
|
||||
pendingTools.push(buildToolTrailLine(name, ctx))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (typeof text !== 'string' || !text.trim()) continue
|
||||
if (typeof text !== 'string' || !text.trim()) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (role === 'assistant') {
|
||||
const msg: Msg = { role, text }
|
||||
|
||||
if (pendingTools.length) {
|
||||
msg.tools = pendingTools
|
||||
pendingTools = []
|
||||
}
|
||||
|
||||
result.push(msg)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -2008,6 +2024,7 @@ export function App({ gw }: { gw: GatewayClient }) {
|
|||
<ToolTrail
|
||||
activity={busy ? activity : []}
|
||||
animateCot={busy && !streaming}
|
||||
padAfter={!!streaming}
|
||||
t={theme}
|
||||
tools={tools}
|
||||
trail={turnTrail}
|
||||
|
|
|
|||
|
|
@ -303,9 +303,12 @@ export function TextInput({ columns = 80, value, onChange, onPaste, onSubmit, pl
|
|||
// ── Input handler ────────────────────────────────────────────────
|
||||
|
||||
useInput(
|
||||
(inp, k) => {
|
||||
// Paste hotkey
|
||||
if ((k.ctrl || k.meta) && inp.toLowerCase() === 'v') {
|
||||
(inp, k, event) => {
|
||||
// Some terminals normalize Ctrl+V to "v"; others deliver raw ^V (\x16).
|
||||
const ctrlPaste = k.ctrl && (inp.toLowerCase() === 'v' || event.keypress.raw === '\x16')
|
||||
const metaPaste = k.meta && inp.toLowerCase() === 'v'
|
||||
|
||||
if (ctrlPaste || metaPaste) {
|
||||
return void emitPaste({ cursor: curRef.current, hotkey: true, text: '', value: vRef.current })
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,13 +48,15 @@ export const ToolTrail = memo(function ToolTrail({
|
|||
tools = [],
|
||||
trail = [],
|
||||
activity = [],
|
||||
animateCot = false
|
||||
animateCot = false,
|
||||
padAfter = false
|
||||
}: {
|
||||
t: Theme
|
||||
tools?: ActiveTool[]
|
||||
trail?: string[]
|
||||
activity?: ActivityItem[]
|
||||
animateCot?: boolean
|
||||
padAfter?: boolean
|
||||
}) {
|
||||
if (!trail.length && !tools.length && !activity.length) {
|
||||
return null
|
||||
|
|
@ -68,6 +70,7 @@ export const ToolTrail = memo(function ToolTrail({
|
|||
<>
|
||||
{trail.map((line, i) => {
|
||||
const lastInBlock = i === rowCount - 1
|
||||
const suffix = padAfter && lastInBlock ? '\n' : ''
|
||||
|
||||
if (isToolTrailResultLine(line)) {
|
||||
return (
|
||||
|
|
@ -78,6 +81,7 @@ export const ToolTrail = memo(function ToolTrail({
|
|||
>
|
||||
<TreeFork last={lastInBlock} />
|
||||
{line}
|
||||
{suffix}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
|
@ -87,6 +91,7 @@ export const ToolTrail = memo(function ToolTrail({
|
|||
<Text color={t.color.dim} key={`c-${i}`}>
|
||||
<TreeFork last={lastInBlock} />
|
||||
<Spinner color={t.color.amber} variant="think" /> {line}
|
||||
{suffix}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
|
@ -95,29 +100,34 @@ export const ToolTrail = memo(function ToolTrail({
|
|||
<Text color={t.color.dim} dimColor key={`c-${i}`}>
|
||||
<TreeFork last={lastInBlock} />
|
||||
{line}
|
||||
{suffix}
|
||||
</Text>
|
||||
)
|
||||
})}
|
||||
|
||||
{tools.map((tool, j) => {
|
||||
const lastInBlock = trail.length + j === rowCount - 1
|
||||
const suffix = padAfter && lastInBlock ? '\n' : ''
|
||||
|
||||
return (
|
||||
<Text color={t.color.dim} key={tool.id}>
|
||||
<TreeFork last={lastInBlock} />
|
||||
<Spinner color={t.color.amber} variant="tool" /> {TOOL_VERBS[tool.name] ?? tool.name}
|
||||
{tool.context ? `: ${tool.context}` : ''}
|
||||
{suffix}
|
||||
</Text>
|
||||
)
|
||||
})}
|
||||
|
||||
{act.map((item, k) => {
|
||||
const lastInBlock = trail.length + tools.length + k === rowCount - 1
|
||||
const suffix = padAfter && lastInBlock ? '\n' : ''
|
||||
|
||||
return (
|
||||
<Text color={tone(item, t)} dimColor={item.tone === 'info'} key={`a-${item.id}`}>
|
||||
<TreeFork last={lastInBlock} />
|
||||
{activityGlyph(item)} {item.text}
|
||||
{suffix}
|
||||
</Text>
|
||||
)
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ export const compactPreview = (s: string, max: number) => {
|
|||
export const buildToolTrailLine = (name: string, context: string, error?: boolean): string => {
|
||||
const label = TOOL_VERBS[name] ?? name
|
||||
const mark = error ? '✗' : '✓'
|
||||
|
||||
return `${label}${context ? ': ' + compactPreview(context, 72) : ''} ${mark}`
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue