@chroxify/eunoe 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +364 -239
- package/package.json +20 -3
- package/src/cli/{types.ts → command.ts} +1 -4
- package/src/cli/commands/index.ts +27 -3
- package/src/cli/commands/load.ts +44 -0
- package/src/cli/commands/mode.ts +68 -24
- package/src/cli/commands/peek.ts +22 -0
- package/src/cli/commands/replay.ts +194 -0
- package/src/cli/commands/serve.ts +24 -8
- package/src/cli/commands/sessions.ts +70 -0
- package/src/cli/commands/settings.ts +119 -0
- package/src/cli/commands/start.ts +73 -0
- package/src/cli/commands/status.ts +107 -30
- package/src/cli/commands/stop.ts +36 -12
- package/src/cli/commands/uninstall.ts +14 -14
- package/src/cli/commands/watch.ts +16 -0
- package/src/cli/logo/art.ts +99 -0
- package/src/cli/logo/index.ts +12 -18
- package/src/cli/main.ts +3 -3
- package/src/cli/proxy/claude-settings.ts +59 -0
- package/src/cli/proxy/inspect.ts +67 -0
- package/src/cli/proxy/launchd.ts +53 -0
- package/src/cli/proxy/service.ts +53 -0
- package/src/cli/proxy/stats.ts +81 -0
- package/src/cli/proxy/watch.ts +60 -0
- package/src/cli/replay/index.ts +141 -0
- package/src/cli/replay/worker.ts +15 -0
- package/src/cli/sessions/browse.ts +88 -0
- package/src/cli/sessions/index.ts +76 -0
- package/src/cli/sessions/source.ts +74 -0
- package/src/cli/{args.ts → terminal/args.ts} +1 -1
- package/src/cli/{help.ts → terminal/help.ts} +25 -9
- package/src/cli/terminal/prompt.ts +114 -0
- package/src/cli/terminal/ui.ts +137 -0
- package/src/config/index.ts +128 -14
- package/src/config/{constants.ts → paths.ts} +4 -14
- package/src/context/content.ts +51 -3
- package/src/context/fold/evidence.ts +145 -0
- package/src/context/fold/index.ts +65 -0
- package/src/context/fold/strategies.ts +94 -0
- package/src/context/fold/turns.ts +76 -0
- package/src/context/prompts.ts +141 -22
- package/src/context/recall/index.ts +214 -0
- package/src/context/recall/rerank.ts +71 -0
- package/src/proxy/canonical.ts +40 -0
- package/src/proxy/compaction.ts +122 -52
- package/src/proxy/estimate.ts +14 -9
- package/src/proxy/fingerprint.ts +29 -0
- package/src/proxy/handoff.ts +71 -0
- package/src/proxy/log.ts +2 -2
- package/src/proxy/recall.ts +58 -0
- package/src/proxy/rewrite.ts +152 -56
- package/src/proxy/server.ts +122 -47
- package/src/proxy/sessions.ts +64 -0
- package/src/proxy/state.ts +17 -3
- package/src/proxy/usage.ts +50 -34
- package/src/proxy/window.ts +32 -34
- package/src/transcript/format.ts +88 -25
- package/src/transcript/locate.ts +38 -17
- package/src/transcript/messages.ts +18 -0
- package/src/transcript/parse.ts +137 -56
- package/src/transcript/render.ts +44 -17
- package/src/transcript/search.ts +20 -56
- package/src/transcript/subagents.ts +150 -0
- package/src/cli/claude-settings.ts +0 -42
- package/src/cli/commands/install.ts +0 -44
- package/src/cli/constants.ts +0 -29
- package/src/cli/inspect.ts +0 -41
- package/src/cli/launchd.ts +0 -34
- package/src/cli/logo/pixels.ts +0 -34
- package/src/cli/ui.ts +0 -91
- package/src/config/types.ts +0 -21
- package/src/context/constants.ts +0 -7
- package/src/context/strategies.ts +0 -89
- package/src/context/turns.ts +0 -82
- package/src/context/types.ts +0 -24
- package/src/proxy/constants.ts +0 -19
- package/src/proxy/types.ts +0 -58
- package/src/transcript/constants.ts +0 -16
- package/src/transcript/types.ts +0 -43
package/src/config/types.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export type Mode = "off" | "trim" | "compact"
|
|
2
|
-
export type SearchMode = "jsonl" | "markdown" | "xml" | "qmd"
|
|
3
|
-
|
|
4
|
-
export interface EvalConfig {
|
|
5
|
-
strategy?: "tail" | "guide"
|
|
6
|
-
tailTurns?: number
|
|
7
|
-
forceCut?: boolean
|
|
8
|
-
trustHeaders?: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface Config {
|
|
12
|
-
mode: Mode
|
|
13
|
-
port: number
|
|
14
|
-
compactAt: number
|
|
15
|
-
keepTurns: number | "all"
|
|
16
|
-
search: SearchMode
|
|
17
|
-
upstream: string
|
|
18
|
-
claudeConfigDirs: string[]
|
|
19
|
-
window?: number
|
|
20
|
-
eval?: EvalConfig
|
|
21
|
-
}
|
package/src/context/constants.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { CLEARED_INPUT_KEPT, CLEARED_INPUT_THRESHOLD } from "./constants"
|
|
2
|
-
import { blocks, withoutCacheControl } from "./content"
|
|
3
|
-
import { compactionNotice, truncationNotice } from "./prompts"
|
|
4
|
-
import { hasContent, isHarness, reduceTurn, splitTurns } from "./turns"
|
|
5
|
-
import type { Block, Body, CompactOptions, Message } from "./types"
|
|
6
|
-
|
|
7
|
-
export function trimMessages(messages: Message[]): Message[] {
|
|
8
|
-
const { preamble, turns } = splitTurns(messages)
|
|
9
|
-
if (turns.length < 2) return messages
|
|
10
|
-
return [...preamble, ...turns.slice(0, -1).flatMap(reduceTurn), ...turns.at(-1)!]
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function compactMessages(
|
|
14
|
-
messages: Message[],
|
|
15
|
-
cutIndex: number,
|
|
16
|
-
options: CompactOptions,
|
|
17
|
-
): Message[] {
|
|
18
|
-
const { preamble, turns } = splitTurns(messages)
|
|
19
|
-
if (cutIndex <= 0 || cutIndex >= turns.length) return messages
|
|
20
|
-
const keptFrom = Math.max(1, cutIndex - options.keepTurns)
|
|
21
|
-
const notice = compactionNotice({ omitted: keptFrom - 1 + (options.omittedBefore ?? 0), kept: cutIndex - keptFrom, guide: options.guide })
|
|
22
|
-
const removed = [...turns[0].slice(1), ...turns.slice(1, keptFrom).flat()]
|
|
23
|
-
const carried = removed
|
|
24
|
-
.filter((m) => isHarness(m) && hasContent(m))
|
|
25
|
-
.flatMap((m) => blocks(m).filter((b) => b.type === "text"))
|
|
26
|
-
.map((b) => ({ type: "text", text: `<system-reminder>\n${b.text}\n</system-reminder>` }))
|
|
27
|
-
return [
|
|
28
|
-
...preamble,
|
|
29
|
-
turns[0][0],
|
|
30
|
-
{ role: "user", content: [{ type: "text", text: notice }, ...carried] },
|
|
31
|
-
...turns.slice(keptFrom, cutIndex).flatMap(reduceTurn),
|
|
32
|
-
...turns.slice(cutIndex).flat(),
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function tailMessages(messages: Message[], from: number, guide: string | null): Message[] {
|
|
37
|
-
const { preamble, turns } = splitTurns(messages)
|
|
38
|
-
if (turns.length === 0 || from <= 1) return messages
|
|
39
|
-
const notice = truncationNotice({ omitted: from - 1, kept: turns.length - from, guide })
|
|
40
|
-
return [
|
|
41
|
-
...preamble,
|
|
42
|
-
turns[0][0],
|
|
43
|
-
{ role: "user", content: [{ type: "text", text: notice }] },
|
|
44
|
-
...turns.slice(from).flat(),
|
|
45
|
-
]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function countToolResults(messages: Message[], from: number): number {
|
|
49
|
-
return messages.slice(from).reduce((total, m) => total + (m.role === "user" ? blocks(m).filter((b) => b.type === "tool_result").length : 0), 0)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function clearToolResults(messages: Message[], from: number, count: number, placeholder: string): Message[] {
|
|
53
|
-
let left = count
|
|
54
|
-
const cleared = new Set<string>()
|
|
55
|
-
const results = messages.map((message, index) => {
|
|
56
|
-
if (left <= 0 || index < from || message.role !== "user" || typeof message.content === "string") return message
|
|
57
|
-
if (!message.content.some((b) => b.type === "tool_result")) return message
|
|
58
|
-
return {
|
|
59
|
-
...message,
|
|
60
|
-
content: message.content.map((b) => {
|
|
61
|
-
if (b.type !== "tool_result" || left <= 0) return b
|
|
62
|
-
left -= 1
|
|
63
|
-
cleared.add(b.tool_use_id)
|
|
64
|
-
return { type: "tool_result", tool_use_id: b.tool_use_id, ...(b.is_error ? { is_error: true } : {}), content: placeholder }
|
|
65
|
-
}),
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
return results.map((message) => {
|
|
69
|
-
if (message.role !== "assistant" || typeof message.content === "string") return message
|
|
70
|
-
if (!message.content.some((b) => b.type === "tool_use" && cleared.has(b.id))) return message
|
|
71
|
-
return { ...message, content: message.content.map((b) => (b.type === "tool_use" && cleared.has(b.id) ? { ...b, input: shortenInput(b.input) } : b)) }
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function shortenInput(input: unknown): unknown {
|
|
76
|
-
if (typeof input === "string") return input.length > CLEARED_INPUT_THRESHOLD ? `${input.slice(0, CLEARED_INPUT_KEPT)}… [${input.length - CLEARED_INPUT_KEPT} chars cleared; in the transcript]` : input
|
|
77
|
-
if (Array.isArray(input)) return input.map(shortenInput)
|
|
78
|
-
if (input && typeof input === "object") return Object.fromEntries(Object.entries(input).map(([k, v]) => [k, shortenInput(v)]))
|
|
79
|
-
return input
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function appendSystem(system: Body["system"], text: string): Block[] {
|
|
83
|
-
const list: Block[] = typeof system === "string" ? [{ type: "text", text: system }] : [...(system ?? [])]
|
|
84
|
-
const lastCached = list.findLastIndex((b) => b.cache_control)
|
|
85
|
-
const cacheControl = lastCached >= 0 ? list[lastCached].cache_control : undefined
|
|
86
|
-
if (lastCached >= 0) list[lastCached] = withoutCacheControl(list[lastCached])
|
|
87
|
-
list.push({ type: "text", text, ...(cacheControl ? { cache_control: cacheControl } : {}) })
|
|
88
|
-
return list
|
|
89
|
-
}
|
package/src/context/turns.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { SUMMARY_ARGUMENT_CHARS, SUMMARY_CALLS_SHOWN, SUMMARY_COMMAND_CHARS, SUMMARY_LAST_WORDS_CHARS } from "./constants"
|
|
2
|
-
import { blocks, clean, clip, withoutCacheControl } from "./content"
|
|
3
|
-
import type { Block, Message } from "./types"
|
|
4
|
-
|
|
5
|
-
export function isPrompt(message: Message) {
|
|
6
|
-
if (message.role !== "user") return false
|
|
7
|
-
const content = blocks(message)
|
|
8
|
-
return !content.some((block) => block.type === "tool_result")
|
|
9
|
-
&& content.some((block) => block.type === "text" || block.type === "image" || block.type === "document")
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function splitTurns(messages: Message[]): { preamble: Message[]; turns: Message[][] } {
|
|
13
|
-
const preamble: Message[] = []
|
|
14
|
-
const turns: Message[][] = []
|
|
15
|
-
for (const message of messages) {
|
|
16
|
-
if (isPrompt(message) && !(turns.length > 0 && turns.at(-1)!.every((m) => m.role === "user"))) {
|
|
17
|
-
turns.push([message])
|
|
18
|
-
} else if (turns.length > 0) {
|
|
19
|
-
turns.at(-1)!.push(message)
|
|
20
|
-
} else {
|
|
21
|
-
preamble.push(message)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return { preamble, turns }
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function turnFingerprint(turn: Message[]): string {
|
|
28
|
-
const hasher = new Bun.CryptoHasher("sha256")
|
|
29
|
-
hasher.update(JSON.stringify(blocks(turn[0]).map(withoutCacheControl)))
|
|
30
|
-
return hasher.digest("hex").slice(0, 24)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function isHarness(message: Message) {
|
|
34
|
-
return message.role === "system"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function hasContent(message: Message) {
|
|
38
|
-
return blocks(message).some((block) => block.type !== "text" || String(block.text ?? "").trim())
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function mergedHarness(turn: Message[]): Message[] {
|
|
42
|
-
const content = turn.filter((m) => isHarness(m) && hasContent(m)).flatMap((m) => blocks(m).map(withoutCacheControl))
|
|
43
|
-
return content.length > 0 ? [{ role: "system", content }] : []
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function describeToolCall(block: Block): string {
|
|
47
|
-
const input = block.input ?? {}
|
|
48
|
-
if (typeof input.command === "string") return `${block.name} \`${clip(input.command, SUMMARY_COMMAND_CHARS)}\``
|
|
49
|
-
if (typeof input.file_path === "string") return `${block.name} ${input.file_path}`
|
|
50
|
-
if (typeof input.pattern === "string") return `${block.name} "${clip(input.pattern, SUMMARY_ARGUMENT_CHARS)}"`
|
|
51
|
-
return `${block.name} ${clip(JSON.stringify(input), SUMMARY_ARGUMENT_CHARS)}`
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function interruptedSummary(turn: Message[]): string {
|
|
55
|
-
const assistant = turn.filter((m) => m.role === "assistant")
|
|
56
|
-
const lastWords = [...assistant].reverse()
|
|
57
|
-
.map((m) => blocks(m).filter((b) => b.type === "text").map((b) => String(b.text ?? "")).join("\n").trim())
|
|
58
|
-
.find(Boolean)
|
|
59
|
-
const calls = assistant.flatMap((m) => blocks(m).filter((b) => b.type === "tool_use")).map(describeToolCall)
|
|
60
|
-
const shown = calls.slice(-SUMMARY_CALLS_SHOWN)
|
|
61
|
-
return [
|
|
62
|
-
"[This turn was interrupted before a final reply.]",
|
|
63
|
-
lastWords ? `Last thing you said: ${lastWords.length > SUMMARY_LAST_WORDS_CHARS ? `${lastWords.slice(0, SUMMARY_LAST_WORDS_CHARS)}…` : lastWords}` : "",
|
|
64
|
-
calls.length > 0 ? `Tool calls (${calls.length}${calls.length > shown.length ? `, last ${shown.length} shown` : ""}): ${shown.join("; ")}` : "",
|
|
65
|
-
"Their output is in the full transcript.",
|
|
66
|
-
].filter(Boolean).join("\n")
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function reduceTurn(turn: Message[]): Message[] {
|
|
70
|
-
const opening: Message[] = []
|
|
71
|
-
for (let i = 0; i < turn.length && turn[i].role !== "assistant"; i += 1) {
|
|
72
|
-
if (turn[i].role === "user") opening.push(clean(turn[i]))
|
|
73
|
-
}
|
|
74
|
-
opening.push(...mergedHarness(turn))
|
|
75
|
-
const last = [...turn].reverse().find((m) => m.role !== "system")!
|
|
76
|
-
const content = last.role === "assistant" ? blocks(last) : []
|
|
77
|
-
const text = content.filter((b) => b.type === "text" && String(b.text ?? "").trim())
|
|
78
|
-
const final = text.length > 0 && !content.some((b) => b.type === "tool_use")
|
|
79
|
-
? text.map((b) => ({ type: "text", text: b.text }))
|
|
80
|
-
: [{ type: "text", text: interruptedSummary(turn) }]
|
|
81
|
-
return [...opening, { role: "assistant", content: final }]
|
|
82
|
-
}
|
package/src/context/types.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export type Block = { type: string; [key: string]: any }
|
|
2
|
-
|
|
3
|
-
export type Message = { role: string; content: string | Block[] }
|
|
4
|
-
|
|
5
|
-
export type Body = {
|
|
6
|
-
model?: string
|
|
7
|
-
system?: string | Block[]
|
|
8
|
-
messages: Message[]
|
|
9
|
-
tools?: unknown[]
|
|
10
|
-
metadata?: { user_id?: string }
|
|
11
|
-
[key: string]: any
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface CompactOptions {
|
|
15
|
-
keepTurns: number
|
|
16
|
-
guide: string | null
|
|
17
|
-
omittedBefore?: number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface NoticeCounts {
|
|
21
|
-
omitted: number
|
|
22
|
-
kept: number
|
|
23
|
-
guide: string | null
|
|
24
|
-
}
|
package/src/proxy/constants.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export const HEALTH_PATH = "/_eunoe/health"
|
|
2
|
-
export const SESSION_HEADER = "x-claude-code-session-id"
|
|
3
|
-
export const TRANSCRIPT_HEADER = "x-eunoe-transcript"
|
|
4
|
-
export const OMITTED_BEFORE_HEADER = "x-eunoe-omitted-before"
|
|
5
|
-
|
|
6
|
-
export const TARGET_SHARE = 0.3
|
|
7
|
-
export const PROTECTED_OUTPUTS = 5
|
|
8
|
-
|
|
9
|
-
export const DEFAULT_RATIO = 1 / 3.6
|
|
10
|
-
export const MEDIA_CHARS = 5_800
|
|
11
|
-
export const MEDIA_MIN_LENGTH = 2_000
|
|
12
|
-
|
|
13
|
-
export const MODEL_HEADERS = ["authorization", "x-api-key", "anthropic-version", "anthropic-beta"]
|
|
14
|
-
export const ANTHROPIC_VERSION = "2023-06-01"
|
|
15
|
-
export const MODEL_LOOKUP_TIMEOUT_MS = 5_000
|
|
16
|
-
|
|
17
|
-
export const MAX_EVENT_BUFFER = 4_000_000
|
|
18
|
-
export const LOGGED_ERROR_CHARS = 500
|
|
19
|
-
export const IDLE_TIMEOUT_SECONDS = 255
|
package/src/proxy/types.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type { Config } from "../config/types"
|
|
2
|
-
import type { Body, Message } from "../context/types"
|
|
3
|
-
import type { TranscriptRef } from "../transcript/types"
|
|
4
|
-
|
|
5
|
-
export interface ThreadState {
|
|
6
|
-
cut?: string
|
|
7
|
-
keep?: number
|
|
8
|
-
cleared?: number
|
|
9
|
-
ratio?: number
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type Note = Record<string, unknown>
|
|
13
|
-
|
|
14
|
-
export interface RewriteInput {
|
|
15
|
-
body: Body
|
|
16
|
-
sessionId: string | null
|
|
17
|
-
config: Config
|
|
18
|
-
transcript: TranscriptRef | null
|
|
19
|
-
window: number | null
|
|
20
|
-
mayCompact: boolean
|
|
21
|
-
omittedBefore?: number
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface Rewrite {
|
|
25
|
-
body: Body
|
|
26
|
-
threadKey: string | null
|
|
27
|
-
note: Note
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface CompactInput {
|
|
31
|
-
body: Body
|
|
32
|
-
config: Config
|
|
33
|
-
state: ThreadState
|
|
34
|
-
window: number | null
|
|
35
|
-
guide: string | null
|
|
36
|
-
mayCompact: boolean
|
|
37
|
-
omittedBefore?: number
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface CompactResult {
|
|
41
|
-
messages: Message[]
|
|
42
|
-
stateChanged: boolean
|
|
43
|
-
note: Note
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface Estimator {
|
|
47
|
-
of: (messages: Message[]) => number
|
|
48
|
-
fixed: number
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export type Usage = Record<string, number>
|
|
52
|
-
|
|
53
|
-
export interface Health {
|
|
54
|
-
ok: boolean
|
|
55
|
-
version: string
|
|
56
|
-
mode: Config["mode"]
|
|
57
|
-
pid: number
|
|
58
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export const OUTPUT_CAP = 40_000
|
|
2
|
-
|
|
3
|
-
export const CALL_COMMAND_CHARS = 300
|
|
4
|
-
export const CALL_PATTERN_CHARS = 120
|
|
5
|
-
export const CALL_DESCRIPTION_CHARS = 160
|
|
6
|
-
export const CALL_INPUT_CHARS = 200
|
|
7
|
-
|
|
8
|
-
export const INDEX_PROMPT_CHARS = 140
|
|
9
|
-
export const INDEX_REPLY_CHARS = 160
|
|
10
|
-
|
|
11
|
-
export const RENDER_STAMP = ".rendered"
|
|
12
|
-
export const TURN_COUNT_FILE = ".turns"
|
|
13
|
-
export const INDEX_FILE = "index.md"
|
|
14
|
-
export const QMD_DIR = ".qmd"
|
|
15
|
-
|
|
16
|
-
export const SESSION_ID_PATTERN = /^[a-zA-Z0-9-]+$/
|
package/src/transcript/types.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { SearchMode } from "../config/types"
|
|
2
|
-
|
|
3
|
-
export type SessionEntry = Record<string, any>
|
|
4
|
-
|
|
5
|
-
export type TranscriptFormat = "markdown" | "xml"
|
|
6
|
-
|
|
7
|
-
export interface ToolPart {
|
|
8
|
-
kind: "tool"
|
|
9
|
-
n: number
|
|
10
|
-
name: string
|
|
11
|
-
call: string
|
|
12
|
-
body: string
|
|
13
|
-
output: string
|
|
14
|
-
error: boolean
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface SayPart {
|
|
18
|
-
kind: "say"
|
|
19
|
-
text: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type TurnPart = SayPart | ToolPart
|
|
23
|
-
|
|
24
|
-
export interface Turn {
|
|
25
|
-
number: number
|
|
26
|
-
time: string
|
|
27
|
-
prompt: string
|
|
28
|
-
parts: TurnPart[]
|
|
29
|
-
final: string
|
|
30
|
-
calls: number
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface RenderResult {
|
|
34
|
-
dir: string
|
|
35
|
-
changed: boolean
|
|
36
|
-
turns: number
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface TranscriptRef {
|
|
40
|
-
mode: SearchMode
|
|
41
|
-
jsonl: string
|
|
42
|
-
dir: string
|
|
43
|
-
}
|