Compare commits
4 Commits
dev
...
feature/tu
| Author | SHA1 | Date |
|---|---|---|
|
|
2d89c22f52 | |
|
|
9d7cc2c6db | |
|
|
daac4e5599 | |
|
|
dd6e8f093e |
|
|
@ -1101,6 +1101,7 @@ export function Session() {
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={message.role === "assistant"}>
|
<Match when={message.role === "assistant"}>
|
||||||
<AssistantMessage
|
<AssistantMessage
|
||||||
|
index={index()}
|
||||||
last={lastAssistant()?.id === message.id}
|
last={lastAssistant()?.id === message.id}
|
||||||
message={message as AssistantMessage}
|
message={message as AssistantMessage}
|
||||||
parts={sync.data.part[message.id] ?? []}
|
parts={sync.data.part[message.id] ?? []}
|
||||||
|
|
@ -1269,7 +1270,7 @@ function UserMessage(props: {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; last: boolean }) {
|
function AssistantMessage(props: { index: number; message: AssistantMessage; parts: Part[]; last: boolean }) {
|
||||||
const local = useLocal()
|
const local = useLocal()
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const sync = useSync()
|
const sync = useSync()
|
||||||
|
|
@ -1279,12 +1280,35 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
|
||||||
return props.message.finish && !["tool-calls", "unknown"].includes(props.message.finish)
|
return props.message.finish && !["tool-calls", "unknown"].includes(props.message.finish)
|
||||||
})
|
})
|
||||||
|
|
||||||
const duration = createMemo(() => {
|
const stats = createMemo(() => {
|
||||||
if (!final()) return 0
|
// if (!final() || !props.message.time.completed) return null
|
||||||
if (!props.message.time.completed) return 0
|
|
||||||
const user = messages().find((x) => x.role === "user" && x.id === props.message.parentID)
|
const list = messages()
|
||||||
if (!user || !user.time) return 0
|
const stats = {
|
||||||
return props.message.time.completed - user.time.created
|
duration: 0,
|
||||||
|
tps: [] as number[],
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = props.index; i >= 0; i--) {
|
||||||
|
const msg = list[i]
|
||||||
|
|
||||||
|
if (msg.id === props.message.parentID && msg.role === "user") {
|
||||||
|
stats.duration = (props.message.time.completed ?? Date.now()) - msg.time.created
|
||||||
|
return {
|
||||||
|
duration: (props.message.time.completed ?? Date.now()) - msg.time.created,
|
||||||
|
tps: stats.tps.reduce((sum, x) => sum + x, 0) / stats.tps.length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (msg.role === "assistant") {
|
||||||
|
if (msg.tokens.output && msg.time.started && msg.time.streamed) {
|
||||||
|
const duration = msg.time.streamed - msg.time.started
|
||||||
|
const tps = msg.tokens.output / (duration / 1000)
|
||||||
|
stats.tps.push(tps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -1334,8 +1358,14 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
<span style={{ fg: theme.text }}>{Locale.titlecase(props.message.mode)}</span>
|
<span style={{ fg: theme.text }}>{Locale.titlecase(props.message.mode)}</span>
|
||||||
<span style={{ fg: theme.textMuted }}> · {props.message.modelID}</span>
|
<span style={{ fg: theme.textMuted }}> · {props.message.modelID}</span>
|
||||||
<Show when={duration()}>
|
<Show when={stats()}>
|
||||||
<span style={{ fg: theme.textMuted }}> · {Locale.duration(duration())}</span>
|
{(s) => (
|
||||||
|
<span style={{ fg: theme.textMuted }}>
|
||||||
|
{" "}
|
||||||
|
· {Locale.duration(s().duration)}
|
||||||
|
<Show when={s().tps > 0}> · {s().tps.toFixed(0)} tok/s</Show>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.message.error?.name === "MessageAbortedError"}>
|
<Show when={props.message.error?.name === "MessageAbortedError"}>
|
||||||
<span style={{ fg: theme.textMuted }}> · interrupted</span>
|
<span style={{ fg: theme.textMuted }}> · interrupted</span>
|
||||||
|
|
|
||||||
|
|
@ -392,6 +392,8 @@ export namespace MessageV2 {
|
||||||
role: z.literal("assistant"),
|
role: z.literal("assistant"),
|
||||||
time: z.object({
|
time: z.object({
|
||||||
created: z.number(),
|
created: z.number(),
|
||||||
|
started: z.number().optional(),
|
||||||
|
streamed: z.number().optional(),
|
||||||
completed: z.number().optional(),
|
completed: z.number().optional(),
|
||||||
}),
|
}),
|
||||||
error: z
|
error: z
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ export namespace SessionProcessor {
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case "start":
|
case "start":
|
||||||
SessionStatus.set(input.sessionID, { type: "busy" })
|
SessionStatus.set(input.sessionID, { type: "busy" })
|
||||||
|
input.assistantMessage.time.started = Date.now()
|
||||||
|
await Session.updateMessage(input.assistantMessage)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "reasoning-start":
|
case "reasoning-start":
|
||||||
|
|
@ -334,6 +336,8 @@ export namespace SessionProcessor {
|
||||||
await Session.updatePart(currentText)
|
await Session.updatePart(currentText)
|
||||||
}
|
}
|
||||||
currentText = undefined
|
currentText = undefined
|
||||||
|
input.assistantMessage.time.streamed = Date.now()
|
||||||
|
await Session.updateMessage(input.assistantMessage)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "finish":
|
case "finish":
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,8 @@ export type AssistantMessage = {
|
||||||
role: "assistant"
|
role: "assistant"
|
||||||
time: {
|
time: {
|
||||||
created: number
|
created: number
|
||||||
|
started?: number
|
||||||
|
streamed?: number
|
||||||
completed?: number
|
completed?: number
|
||||||
}
|
}
|
||||||
error?:
|
error?:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue