praxis-agent 0.34.0 → 0.35.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 +4 -0
- package/dist/application/session-service.d.ts +0 -1
- package/dist/application/session-service.js +1619 -1617
- package/dist/application/subagent-service.js +27 -16
- package/dist/application/turn-lifecycle.d.ts +38 -0
- package/dist/application/turn-lifecycle.js +36 -0
- package/dist/cli/interactive.js +17 -7
- package/dist/cli/protocol.js +5 -2
- package/dist/cli/tui/claude-style.d.ts +5 -48
- package/dist/cli/tui/claude-style.js +19 -73
- package/dist/cli/tui/transcript-presentation.d.ts +89 -0
- package/dist/cli/tui/transcript-presentation.js +169 -0
- package/dist/cli/tui/transcript-viewport.d.ts +5 -34
- package/dist/cli/tui/transcript-viewport.js +639 -158
- package/dist/cli/tui/tui-view-model.d.ts +6 -2
- package/dist/cli/tui/tui-view-model.js +23 -6
- package/dist/compatibility/claude/context.d.ts +2 -2
- package/dist/compatibility/claude/context.js +2 -14
- package/dist/compatibility/claude/data-plane-adapter.d.ts +9 -0
- package/dist/compatibility/claude/data-plane-adapter.js +44 -0
- package/dist/compatibility/claude/paths.js +2 -2
- package/dist/compatibility/claude/shared-resources.d.ts +7 -38
- package/dist/compatibility/claude/transcript-codec.d.ts +21 -0
- package/dist/compatibility/claude/transcript-codec.js +512 -0
- package/dist/core/context.d.ts +25 -7
- package/dist/core/context.js +46 -0
- package/dist/core/prompt-composer.d.ts +8 -16
- package/dist/core/prompt-composer.js +65 -25
- package/dist/core/resources.d.ts +39 -0
- package/dist/core/resources.js +2 -0
- package/dist/core/runtime.d.ts +1 -1
- package/dist/core/session.d.ts +2 -0
- package/dist/core/session.js +5 -0
- package/dist/core/transcript-codec.d.ts +70 -0
- package/dist/core/transcript-codec.js +60 -0
- package/dist/core/transcript-event.d.ts +33 -0
- package/dist/core/transcript-event.js +198 -0
- package/dist/persistence/data-plane-adapter.d.ts +32 -0
- package/dist/persistence/data-plane-adapter.js +2 -0
- package/dist/persistence/data-plane.d.ts +4 -20
- package/dist/persistence/data-plane.js +10 -47
- package/dist/persistence/native-data-plane-adapter.d.ts +9 -0
- package/dist/persistence/native-data-plane-adapter.js +39 -0
- package/dist/persistence/native-resources.d.ts +4 -4
- package/dist/persistence/native-transcript-codec.d.ts +13 -0
- package/dist/persistence/native-transcript-codec.js +102 -0
- package/dist/tools/claude-user-message.d.ts +0 -1
- package/dist/tools/claude-user-message.js +0 -1
- package/package.json +6 -2
|
@@ -8,7 +8,8 @@ import { createClaudeAsyncAgentToolUseResult, createClaudeAgentToolUseResult, cr
|
|
|
8
8
|
import { projectClaudeModelMessages, projectClaudeSidechainContinuationMessages, } from '../compatibility/claude/projection.js';
|
|
9
9
|
import { selectClaudeSchemaAdapter, } from '../compatibility/claude/schema.js';
|
|
10
10
|
import { createClaudeHookAttachmentEntries, translateProviderEvents, } from '../compatibility/claude/translation.js';
|
|
11
|
-
import { injectFirstUserMessageContext, } from '../core/context.js';
|
|
11
|
+
import { injectFirstUserMessageContext, projectContextSnapshot, } from '../core/context.js';
|
|
12
|
+
import { assembleContextSnapshot } from '../core/prompt-composer.js';
|
|
12
13
|
import { ContextBudget } from '../core/context-budget.js';
|
|
13
14
|
import { AgentRuntime, } from '../core/runtime.js';
|
|
14
15
|
import { resolveToolSchedulingPolicy } from '../core/tool-scheduling-policy.js';
|
|
@@ -1995,9 +1996,6 @@ export class ClaudeSubagentExecutor {
|
|
|
1995
1996
|
const agentSystem = memoryPrompt
|
|
1996
1997
|
? `${baseSystem}\n\n${memoryPrompt}`
|
|
1997
1998
|
: baseSystem;
|
|
1998
|
-
const system = options.outputSchema
|
|
1999
|
-
? `${agentSystem}\n\nYou MUST call StructuredOutput exactly once at the end with a value matching its schema.`
|
|
2000
|
-
: agentSystem;
|
|
2001
1999
|
const preloadedSkills = agentSkillMessages(this.options.extensions, customAgent);
|
|
2002
2000
|
let stopHookActive = false;
|
|
2003
2001
|
const contextBudget = options.provider.capabilities.contextWindowTokens
|
|
@@ -2016,22 +2014,28 @@ export class ClaudeSubagentExecutor {
|
|
|
2016
2014
|
? runtimeTools.definitions()
|
|
2017
2015
|
: [];
|
|
2018
2016
|
let observedMessages;
|
|
2017
|
+
let stableSystemMessageCount = 0;
|
|
2019
2018
|
const assembleMessages = async () => {
|
|
2020
|
-
const assembledContext = await this.options.contextAssembler
|
|
2019
|
+
const assembledContext = await assembleContextSnapshot(this.options.contextAssembler, {
|
|
2021
2020
|
cwd,
|
|
2022
2021
|
lifecycleId: options.agentId,
|
|
2023
2022
|
mode: 'subagent',
|
|
2024
|
-
baseSystemPrompt:
|
|
2023
|
+
baseSystemPrompt: agentSystem,
|
|
2024
|
+
...(options.outputSchema
|
|
2025
|
+
? {
|
|
2026
|
+
turn: {
|
|
2027
|
+
structuredOutput: true,
|
|
2028
|
+
},
|
|
2029
|
+
}
|
|
2030
|
+
: {}),
|
|
2025
2031
|
});
|
|
2026
|
-
const
|
|
2032
|
+
const contextProjection = projectContextSnapshot(assembledContext);
|
|
2033
|
+
stableSystemMessageCount = contextProjection.stableSystemSectionCount;
|
|
2027
2034
|
const messages = [
|
|
2028
|
-
...
|
|
2029
|
-
...(composedSubagentPolicy
|
|
2030
|
-
? []
|
|
2031
|
-
: [{ role: 'system', content: system }]),
|
|
2035
|
+
...contextProjection.systemMessages,
|
|
2032
2036
|
...injectFirstUserMessageContext(options.continuationMessage === undefined
|
|
2033
2037
|
? projectClaudeModelMessages(snapshot.entries)
|
|
2034
|
-
: projectClaudeSidechainContinuationMessages(snapshot.entries),
|
|
2038
|
+
: projectClaudeSidechainContinuationMessages(snapshot.entries), contextProjection.firstUserMessageContext),
|
|
2035
2039
|
...preloadedSkills,
|
|
2036
2040
|
];
|
|
2037
2041
|
observedMessages = messages;
|
|
@@ -2042,11 +2046,17 @@ export class ClaudeSubagentExecutor {
|
|
|
2042
2046
|
};
|
|
2043
2047
|
const configuredEffort = typeof customAgent?.effort === 'string' ? customAgent.effort : undefined;
|
|
2044
2048
|
const effectiveEffort = options.effort ?? configuredEffort;
|
|
2045
|
-
const
|
|
2049
|
+
const initialMessages = await assembleMessages();
|
|
2050
|
+
const runtimeRequest = {
|
|
2046
2051
|
sessionId: String(options.root.sessionId),
|
|
2047
|
-
messages:
|
|
2052
|
+
messages: initialMessages,
|
|
2048
2053
|
collectMetrics: true,
|
|
2049
|
-
|
|
2054
|
+
stableSystemMessageCount,
|
|
2055
|
+
reloadMessages: async () => {
|
|
2056
|
+
const messages = await assembleMessages();
|
|
2057
|
+
runtimeRequest.stableSystemMessageCount = stableSystemMessageCount;
|
|
2058
|
+
return messages;
|
|
2059
|
+
},
|
|
2050
2060
|
cwd,
|
|
2051
2061
|
...(effectiveEffort ? { effort: effectiveEffort } : {}),
|
|
2052
2062
|
toolResultDirectory: options.toolResultDirectory,
|
|
@@ -2119,7 +2129,8 @@ export class ClaudeSubagentExecutor {
|
|
|
2119
2129
|
}
|
|
2120
2130
|
: {}),
|
|
2121
2131
|
...(options.signal ? { signal: options.signal } : {}),
|
|
2122
|
-
}
|
|
2132
|
+
};
|
|
2133
|
+
const result = await runtime.run(runtimeRequest);
|
|
2123
2134
|
contextBudget?.observeUsage(result.usage, observedMessages ?? [], definitions);
|
|
2124
2135
|
this.options.eventSink?.({
|
|
2125
2136
|
type: 'task-progress',
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type ModelDocument, type ModelImage, type RuntimeEventSink } from '../core/runtime.js';
|
|
2
|
+
export type TurnActivation = {
|
|
3
|
+
kind: 'start';
|
|
4
|
+
sessionId: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'resume';
|
|
8
|
+
sessionId: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
atMessageId?: string;
|
|
11
|
+
};
|
|
12
|
+
export type TurnSubmission = {
|
|
13
|
+
kind: 'prompt';
|
|
14
|
+
text: string;
|
|
15
|
+
images?: readonly ModelImage[];
|
|
16
|
+
documents?: readonly ModelDocument[];
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'shell';
|
|
19
|
+
command: string;
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'retry';
|
|
22
|
+
prompt: string;
|
|
23
|
+
};
|
|
24
|
+
export interface TurnRequest {
|
|
25
|
+
activation: TurnActivation;
|
|
26
|
+
submission: TurnSubmission;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}
|
|
29
|
+
export declare class TurnTerminalController {
|
|
30
|
+
private readonly sink;
|
|
31
|
+
private terminal;
|
|
32
|
+
constructor(sink: RuntimeEventSink);
|
|
33
|
+
emit: RuntimeEventSink;
|
|
34
|
+
complete(): void;
|
|
35
|
+
fail(error: unknown, signal?: AbortSignal): void;
|
|
36
|
+
private transition;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=turn-lifecycle.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AgentRunCancelledError, ModelProviderError, } from '../core/runtime.js';
|
|
2
|
+
export class TurnTerminalController {
|
|
3
|
+
sink;
|
|
4
|
+
terminal = false;
|
|
5
|
+
constructor(sink) {
|
|
6
|
+
this.sink = sink;
|
|
7
|
+
}
|
|
8
|
+
emit = (event) => {
|
|
9
|
+
if (event.type === 'state' &&
|
|
10
|
+
(event.state === 'completed' ||
|
|
11
|
+
event.state === 'cancelled' ||
|
|
12
|
+
event.state === 'failed')) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
this.sink(event);
|
|
16
|
+
};
|
|
17
|
+
complete() {
|
|
18
|
+
this.transition('completed');
|
|
19
|
+
}
|
|
20
|
+
fail(error, signal) {
|
|
21
|
+
if (this.terminal)
|
|
22
|
+
return;
|
|
23
|
+
const cancelled = signal?.aborted === true ||
|
|
24
|
+
error instanceof AgentRunCancelledError ||
|
|
25
|
+
(error instanceof ModelProviderError && error.kind === 'cancelled');
|
|
26
|
+
this.transition(cancelled ? 'cancelled' : 'failed');
|
|
27
|
+
}
|
|
28
|
+
transition(state) {
|
|
29
|
+
if (this.terminal) {
|
|
30
|
+
throw new Error('Turn terminal transition already emitted');
|
|
31
|
+
}
|
|
32
|
+
this.terminal = true;
|
|
33
|
+
this.sink({ type: 'state', state });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=turn-lifecycle.js.map
|
package/dist/cli/interactive.js
CHANGED
|
@@ -18,7 +18,6 @@ import { loadClaudeReleaseNotes } from './tui/release-notes.js';
|
|
|
18
18
|
import { fullscreenInkRenderOptions } from './tui/fullscreen-renderer.js';
|
|
19
19
|
import { StreamingFrameBuffer } from './tui/streaming-frame-buffer.js';
|
|
20
20
|
import { createClaudeStatusLineInput, StatusLine } from './tui/status-line.js';
|
|
21
|
-
import { FULLSCREEN_TRANSCRIPT_RESERVED_ROWS, transcriptLineCount, } from './tui/transcript-viewport.js';
|
|
22
21
|
import { projectTuiView, resolveTuiRenderer } from './tui/tui-view-model.js';
|
|
23
22
|
import { loadGitDiff, visiblePatchLines, } from './tui/git-diff.js';
|
|
24
23
|
import { addTuiPermissionRule, loadTuiPermissionRules, removeTuiPermissionRule, } from './tui/permission-settings.js';
|
|
@@ -466,7 +465,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
466
465
|
// composer/status chrome intact and keeping the active stream visible.
|
|
467
466
|
// Classic and screen-reader modes always render the full history exactly as
|
|
468
467
|
// before.
|
|
469
|
-
const {
|
|
468
|
+
const { transcriptEntries, transcriptPageRows, maxTranscriptScrollOffset, resumed, freshSession, hasConversationHistory, } = useMemo(() => projectTuiView({
|
|
470
469
|
initialHistory,
|
|
471
470
|
history,
|
|
472
471
|
resume: resume !== undefined,
|
|
@@ -475,7 +474,19 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
475
474
|
rows,
|
|
476
475
|
width,
|
|
477
476
|
scrollOffset: transcriptScrollOffset,
|
|
478
|
-
|
|
477
|
+
detailedTranscript: thinkingExpanded || runtimeSettings.verbose,
|
|
478
|
+
}), [
|
|
479
|
+
initialHistory,
|
|
480
|
+
history,
|
|
481
|
+
resume,
|
|
482
|
+
fixedViewport,
|
|
483
|
+
axScreenReader,
|
|
484
|
+
rows,
|
|
485
|
+
width,
|
|
486
|
+
transcriptScrollOffset,
|
|
487
|
+
thinkingExpanded,
|
|
488
|
+
runtimeSettings.verbose,
|
|
489
|
+
]);
|
|
479
490
|
const sessionLoadRef = useRef(0);
|
|
480
491
|
const [turnDiffs, setTurnDiffs] = useState([]);
|
|
481
492
|
const turnNumberRef = useRef(0);
|
|
@@ -2979,7 +2990,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
2979
2990
|
!question &&
|
|
2980
2991
|
!elicitation &&
|
|
2981
2992
|
!selectingSession) {
|
|
2982
|
-
const page =
|
|
2993
|
+
const page = transcriptPageRows;
|
|
2983
2994
|
const scrollDelta = key.pageUp
|
|
2984
2995
|
? page
|
|
2985
2996
|
: key.pageDown
|
|
@@ -2994,8 +3005,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
2994
3005
|
? -1
|
|
2995
3006
|
: 0;
|
|
2996
3007
|
if (scrollDelta !== 0) {
|
|
2997
|
-
setTranscriptScrollOffset((current) => Math.min(Math.max(0,
|
|
2998
|
-
Math.max(1, (rows ?? 0) - FULLSCREEN_TRANSCRIPT_RESERVED_ROWS)), Math.max(0, current + Math.trunc(scrollDelta))));
|
|
3008
|
+
setTranscriptScrollOffset((current) => Math.min(Math.max(0, maxTranscriptScrollOffset), Math.max(0, current + Math.trunc(scrollDelta))));
|
|
2999
3009
|
return;
|
|
3000
3010
|
}
|
|
3001
3011
|
}
|
|
@@ -5857,7 +5867,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
|
|
|
5857
5867
|
minHeight: 0,
|
|
5858
5868
|
overflowY: 'hidden',
|
|
5859
5869
|
}
|
|
5860
|
-
: {}), children: _jsx(Transcript, {
|
|
5870
|
+
: {}), children: _jsx(Transcript, { entries: transcriptEntries, activeText: activeText, activeThinking: activeThinking, activeStreamVisible: transcriptScrollOffset === 0, thinkingExpanded: thinkingExpanded, detailedTranscript: thinkingExpanded || runtimeSettings.verbose, screenReader: axScreenReader }) }), externalEditorRequest !== null ||
|
|
5861
5871
|
keybindingsEditing ||
|
|
5862
5872
|
memoryEditorRequest !== null ? (_jsx(ExternalEditorWait, { screenReader: axScreenReader })) : permission ? (permission.kind === 'tool' && toolPermissionModel ? (_jsx(ToolPermissionDialog, { model: toolPermissionModel, selection: permissionSelection, feedbackMode: permissionFeedbackMode, feedback: input, ruleEditor: permissionRuleEditor, screenReader: axScreenReader })) : (_jsxs(DialogFrame, { title: `Retry interrupted ${permission.call.name}?`, screenReader: axScreenReader, children: [_jsx(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: _jsx(Text, { bold: true, children: describeTool(permission.call, sensitiveValues) }) }), _jsx(Text, { children: "Do you want to proceed?" }), _jsxs(Text, { inverse: !axScreenReader && permissionSelection === 0, children: [selectionPrefix(permissionSelection === 0, axScreenReader), "1. Yes"] }), _jsxs(Text, { inverse: !axScreenReader && permissionSelection === 1, children: [selectionPrefix(permissionSelection === 1, axScreenReader), "2. No"] }), permissionFeedbackMode ? (_jsxs(Text, { children: ["\u203A", ' ', input ||
|
|
5863
5873
|
(permissionSelection === 0
|
package/dist/cli/protocol.js
CHANGED
|
@@ -1788,11 +1788,14 @@ export class StreamJsonOutput {
|
|
|
1788
1788
|
event.state === 'executing-tools' ||
|
|
1789
1789
|
event.state === 'persisting-results' ||
|
|
1790
1790
|
event.state === 'completed' ||
|
|
1791
|
-
event.state === 'cancelled'
|
|
1791
|
+
event.state === 'cancelled' ||
|
|
1792
|
+
event.state === 'failed') {
|
|
1792
1793
|
this.flushAssistant();
|
|
1793
1794
|
if (event.state === 'awaiting-permission')
|
|
1794
1795
|
this.writeSessionState('requires_action');
|
|
1795
|
-
else if (event.state === 'completed' ||
|
|
1796
|
+
else if (event.state === 'completed' ||
|
|
1797
|
+
event.state === 'cancelled' ||
|
|
1798
|
+
event.state === 'failed') {
|
|
1796
1799
|
this.writeSessionState('idle');
|
|
1797
1800
|
}
|
|
1798
1801
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ModelUsage } from '../../core/runtime.js';
|
|
3
3
|
import type { AgentColorName } from '../../compatibility/claude/agent-color.js';
|
|
4
4
|
import type { DataPlane } from '../../persistence/data-plane.js';
|
|
5
5
|
import type { TuiFileEntry, TuiMentionEntry } from './file-picker.js';
|
|
@@ -10,6 +10,7 @@ import type { TuiPermissionRule } from './permission-settings.js';
|
|
|
10
10
|
import type { RecentlyDeniedAction } from './recently-denied.js';
|
|
11
11
|
import type { CustomThemeToken, TuiCustomTheme } from './custom-themes.js';
|
|
12
12
|
import type { TuiSlashCommand } from './slash-commands.js';
|
|
13
|
+
import type { TranscriptPresentationEntry } from './transcript-presentation.js';
|
|
13
14
|
import { type TuiTheme } from './theme.js';
|
|
14
15
|
export interface TuiDisplayMetadata {
|
|
15
16
|
version: string;
|
|
@@ -19,51 +20,7 @@ export interface TuiDisplayMetadata {
|
|
|
19
20
|
permissionMode?: string;
|
|
20
21
|
contextWindowTokens?: number;
|
|
21
22
|
}
|
|
22
|
-
export type TranscriptItem
|
|
23
|
-
kind: 'user' | 'assistant' | 'notice' | 'warning';
|
|
24
|
-
text: string;
|
|
25
|
-
} | {
|
|
26
|
-
kind: 'local-result';
|
|
27
|
-
text: string;
|
|
28
|
-
} | {
|
|
29
|
-
kind: 'thinking';
|
|
30
|
-
text: string;
|
|
31
|
-
} | {
|
|
32
|
-
kind: 'compact';
|
|
33
|
-
summary: string;
|
|
34
|
-
} | {
|
|
35
|
-
kind: 'context';
|
|
36
|
-
usedTokens: number;
|
|
37
|
-
contextWindowTokens: number;
|
|
38
|
-
model?: string;
|
|
39
|
-
skills: readonly {
|
|
40
|
-
name: string;
|
|
41
|
-
tokens: number;
|
|
42
|
-
}[];
|
|
43
|
-
memoryFiles: readonly {
|
|
44
|
-
path: string;
|
|
45
|
-
tokens: number;
|
|
46
|
-
}[];
|
|
47
|
-
} | {
|
|
48
|
-
kind: 'tool';
|
|
49
|
-
call: ModelToolCall;
|
|
50
|
-
detail: string;
|
|
51
|
-
} | {
|
|
52
|
-
kind: 'tool-result';
|
|
53
|
-
callId: string;
|
|
54
|
-
text: string;
|
|
55
|
-
isError: boolean;
|
|
56
|
-
} | {
|
|
57
|
-
kind: 'shell';
|
|
58
|
-
callId: string;
|
|
59
|
-
command: string;
|
|
60
|
-
} | {
|
|
61
|
-
kind: 'shell-result';
|
|
62
|
-
callId: string;
|
|
63
|
-
stdout: string;
|
|
64
|
-
stderr: string;
|
|
65
|
-
isError: boolean;
|
|
66
|
-
};
|
|
23
|
+
export type { TranscriptItem } from './transcript-presentation.js';
|
|
67
24
|
export interface TuiBtwEntry {
|
|
68
25
|
id: number;
|
|
69
26
|
question: string;
|
|
@@ -92,8 +49,8 @@ export declare function activeStreamWindow(text: string): {
|
|
|
92
49
|
pendingText: string;
|
|
93
50
|
truncated: boolean;
|
|
94
51
|
};
|
|
95
|
-
export declare function Transcript({
|
|
96
|
-
|
|
52
|
+
export declare function Transcript({ entries, activeText, activeThinking, activeStreamVisible, thinkingExpanded, detailedTranscript, screenReader, }: {
|
|
53
|
+
entries: readonly TranscriptPresentationEntry[];
|
|
97
54
|
activeText: string;
|
|
98
55
|
activeThinking?: string;
|
|
99
56
|
activeStreamVisible?: boolean;
|
|
@@ -516,94 +516,42 @@ function ActiveStreamText({ text }) {
|
|
|
516
516
|
const { stableText, pendingText, truncated } = activeStreamWindow(text);
|
|
517
517
|
return (_jsxs(Box, { flexDirection: "column", children: [truncated ? _jsx(Text, { dimColor: true, children: "\u2026 earlier streaming content \u2026" }) : null, stableText ? _jsx(MarkdownText, { text: stableText }) : null, pendingText ? _jsx(Text, { children: pendingText }) : null] }));
|
|
518
518
|
}
|
|
519
|
-
export function Transcript({
|
|
519
|
+
export function Transcript({ entries, activeText, activeThinking = '', activeStreamVisible = true, thinkingExpanded = false, detailedTranscript = false, screenReader, }) {
|
|
520
520
|
const palette = useTuiPalette();
|
|
521
521
|
const detailed = thinkingExpanded || detailedTranscript;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const pairedResults = new Set(items
|
|
526
|
-
.filter((item) => item.kind === 'tool' && results.has(item.call.id))
|
|
527
|
-
.map((item) => item.call.id));
|
|
528
|
-
const shellResults = new Map(items
|
|
529
|
-
.filter((item) => item.kind === 'shell-result')
|
|
530
|
-
.map((item) => [item.callId, item]));
|
|
531
|
-
const pairedShellResults = new Set(items
|
|
532
|
-
.filter((item) => item.kind === 'shell' && shellResults.has(item.callId))
|
|
533
|
-
.map((item) => item.callId));
|
|
534
|
-
const readGroupStarts = new Map();
|
|
535
|
-
const groupedReadTools = new Set();
|
|
536
|
-
if (!detailed && !screenReader) {
|
|
537
|
-
for (let index = 0; index < items.length; index += 1) {
|
|
538
|
-
const first = items[index];
|
|
539
|
-
if (first?.kind !== 'tool' || first.call.name !== 'Read')
|
|
540
|
-
continue;
|
|
541
|
-
let cursor = index;
|
|
542
|
-
const memberIndexes = [];
|
|
543
|
-
const memberCallIds = new Set();
|
|
544
|
-
while (cursor < items.length) {
|
|
545
|
-
const candidate = items[cursor];
|
|
546
|
-
if (candidate?.kind === 'tool' && candidate.call.name === 'Read') {
|
|
547
|
-
const result = results.get(candidate.call.id);
|
|
548
|
-
if (!result || result.isError)
|
|
549
|
-
break;
|
|
550
|
-
memberIndexes.push(cursor);
|
|
551
|
-
memberCallIds.add(candidate.call.id);
|
|
552
|
-
cursor += 1;
|
|
553
|
-
continue;
|
|
522
|
+
return (_jsxs(Box, { flexDirection: "column", children: [entries.map((entry, index) => {
|
|
523
|
+
if (entry.kind === 'read-summary') {
|
|
524
|
+
return (_jsxs(Text, { children: [' ', "Read ", entry.count, " file", entry.count === 1 ? '' : 's', ' ', _jsx(Text, { dimColor: true, children: "(ctrl+o to expand)" })] }, entry.key));
|
|
554
525
|
}
|
|
555
|
-
|
|
556
|
-
memberCallIds.has(candidate.callId)) {
|
|
557
|
-
cursor += 1;
|
|
558
|
-
continue;
|
|
559
|
-
}
|
|
560
|
-
break;
|
|
561
|
-
}
|
|
562
|
-
if (memberIndexes.length === 0)
|
|
563
|
-
continue;
|
|
564
|
-
readGroupStarts.set(index, memberIndexes.length);
|
|
565
|
-
for (const memberIndex of memberIndexes.slice(1)) {
|
|
566
|
-
groupedReadTools.add(memberIndex);
|
|
567
|
-
}
|
|
568
|
-
index = cursor - 1;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
return (_jsxs(Box, { flexDirection: "column", children: [items.map((item, index) => {
|
|
572
|
-
const readCount = readGroupStarts.get(index);
|
|
573
|
-
if (readCount !== undefined) {
|
|
574
|
-
return (_jsxs(Text, { children: [' ', "Read ", readCount, " file", readCount === 1 ? '' : 's', ' ', _jsx(Text, { dimColor: true, children: "(ctrl+o to expand)" })] }, index));
|
|
575
|
-
}
|
|
576
|
-
if (groupedReadTools.has(index))
|
|
577
|
-
return null;
|
|
526
|
+
const item = entry.item;
|
|
578
527
|
if (item.kind === 'user') {
|
|
579
|
-
return (_jsxs(Box, { marginTop: index === 0 ? 0 : 1, children: [_jsx(Text, { color: palette.brand, bold: true, children: screenReader ? 'You: ' : '❯ ' }), _jsx(Text, { bold: true, children: item.text })] },
|
|
528
|
+
return (_jsxs(Box, { marginTop: index === 0 ? 0 : 1, children: [_jsx(Text, { color: palette.brand, bold: true, children: screenReader ? 'You: ' : '❯ ' }), _jsx(Text, { bold: true, children: item.text })] }, entry.key));
|
|
580
529
|
}
|
|
581
530
|
if (item.kind === 'assistant') {
|
|
582
|
-
return (_jsxs(Box, { marginTop: 1, children: [screenReader ? _jsx(Text, { children: "Praxis:" }) : null, !screenReader ? _jsx(Text, { color: palette.accent, children: "\u23FA " }) : null, _jsx(MarkdownText, { text: item.text })] },
|
|
531
|
+
return (_jsxs(Box, { marginTop: 1, children: [screenReader ? _jsx(Text, { children: "Praxis:" }) : null, !screenReader ? _jsx(Text, { color: palette.accent, children: "\u23FA " }) : null, _jsx(MarkdownText, { text: item.text })] }, entry.key));
|
|
583
532
|
}
|
|
584
533
|
if (item.kind === 'thinking') {
|
|
585
|
-
return (_jsx(ThinkingBlock, { text: item.text, active: false, expanded: detailed, screenReader: screenReader },
|
|
534
|
+
return (_jsx(ThinkingBlock, { text: item.text, active: false, expanded: detailed, screenReader: screenReader }, entry.key));
|
|
586
535
|
}
|
|
587
536
|
if (item.kind === 'compact') {
|
|
588
537
|
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: palette.accent, italic: true, children: screenReader
|
|
589
538
|
? 'Conversation compacted'
|
|
590
|
-
: '✻ Conversation compacted (ctrl+o for history)' }), detailed ? (_jsx(Box, { marginLeft: screenReader ? 0 : 2, children: _jsx(MarkdownText, { text: item.summary }) })) : null] },
|
|
539
|
+
: '✻ Conversation compacted (ctrl+o for history)' }), detailed ? (_jsx(Box, { marginLeft: screenReader ? 0 : 2, children: _jsx(MarkdownText, { text: item.summary }) })) : null] }, entry.key));
|
|
591
540
|
}
|
|
592
541
|
if (item.kind === 'context') {
|
|
593
|
-
return (_jsx(ContextUsageBlock, { ...item, screenReader: screenReader },
|
|
542
|
+
return (_jsx(ContextUsageBlock, { ...item, screenReader: screenReader }, entry.key));
|
|
594
543
|
}
|
|
595
544
|
if (item.kind === 'tool') {
|
|
596
|
-
|
|
597
|
-
|
|
545
|
+
return (_jsx(ToolTranscriptEntry, { call: item.call, detail: item.detail, ...(entry.kind === 'tool' && entry.result
|
|
546
|
+
? { result: entry.result }
|
|
547
|
+
: {}), detailed: detailed || screenReader }, entry.key));
|
|
598
548
|
}
|
|
599
549
|
if (item.kind === 'tool-result') {
|
|
600
|
-
if (pairedResults.has(item.callId))
|
|
601
|
-
return null;
|
|
602
550
|
const text = item.text.length > 500 ? `${item.text.slice(0, 497)}...` : item.text;
|
|
603
|
-
return (_jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsx(Text, { color: item.isError ? palette.error : palette.muted, children: item.isError ? '└ Error' : '└ Result' }), item.isError ? (_jsx(Text, { color: palette.error, children: text })) : (_jsx(ToolResultText, { text: text }))] },
|
|
551
|
+
return (_jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsx(Text, { color: item.isError ? palette.error : palette.muted, children: item.isError ? '└ Error' : '└ Result' }), item.isError ? (_jsx(Text, { color: palette.error, children: text })) : (_jsx(ToolResultText, { text: text }))] }, entry.key));
|
|
604
552
|
}
|
|
605
553
|
if (item.kind === 'shell') {
|
|
606
|
-
const result =
|
|
554
|
+
const result = entry.kind === 'shell' ? entry.result : undefined;
|
|
607
555
|
const output = result
|
|
608
556
|
? [result.stdout, result.stderr]
|
|
609
557
|
.filter(Boolean)
|
|
@@ -616,18 +564,16 @@ export function Transcript({ items, activeText, activeThinking = '', activeStrea
|
|
|
616
564
|
const lines = contentLines(output);
|
|
617
565
|
const visible = detailed || screenReader ? lines : lines.slice(0, 3);
|
|
618
566
|
const hidden = lines.length - visible.length;
|
|
619
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { children: _jsxs(Text, { bold: true, children: [screenReader ? 'Shell command: ' : '! ', item.command] }) }), result ? (_jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [lines.length === 0 ? (_jsx(Text, { dimColor: true, children: "\u23BF " })) : (visible.map((line, lineIndex) => (_jsxs(Text, { ...(result.isError ? { color: palette.error } : {}), dimColor: !result.isError, children: [lineIndex === 0 ? '⎿ ' : ' ', line || ' '] }, lineIndex)))), hidden > 0 ? (_jsxs(Text, { dimColor: true, children: [' ', "\u2026 +", hidden, " lines (ctrl+o to expand)"] })) : null] })) : null] },
|
|
567
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { children: _jsxs(Text, { bold: true, children: [screenReader ? 'Shell command: ' : '! ', item.command] }) }), result ? (_jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [lines.length === 0 ? (_jsx(Text, { dimColor: true, children: "\u23BF " })) : (visible.map((line, lineIndex) => (_jsxs(Text, { ...(result.isError ? { color: palette.error } : {}), dimColor: !result.isError, children: [lineIndex === 0 ? '⎿ ' : ' ', line || ' '] }, lineIndex)))), hidden > 0 ? (_jsxs(Text, { dimColor: true, children: [' ', "\u2026 +", hidden, " lines (ctrl+o to expand)"] })) : null] })) : null] }, entry.key));
|
|
620
568
|
}
|
|
621
569
|
if (item.kind === 'shell-result') {
|
|
622
|
-
if (pairedShellResults.has(item.callId))
|
|
623
|
-
return null;
|
|
624
570
|
const output = [item.stdout, item.stderr].filter(Boolean).join('\n');
|
|
625
|
-
return (_jsxs(Text, { ...(item.isError ? { color: palette.error } : {}), children: ["\u23BF ", output] },
|
|
571
|
+
return (_jsxs(Text, { ...(item.isError ? { color: palette.error } : {}), children: ["\u23BF ", output] }, entry.key));
|
|
626
572
|
}
|
|
627
573
|
if (item.kind === 'local-result') {
|
|
628
|
-
return (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { dimColor: true, children: ["\u23BF ", item.text] }) },
|
|
574
|
+
return (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { dimColor: true, children: ["\u23BF ", item.text] }) }, entry.key));
|
|
629
575
|
}
|
|
630
|
-
return (_jsxs(Text, { ...(item.kind === 'warning' ? { color: palette.error } : {}), dimColor: item.kind === 'notice', children: [item.kind === 'warning' ? '⚠ ' : '· ', item.text] },
|
|
576
|
+
return (_jsxs(Text, { ...(item.kind === 'warning' ? { color: palette.error } : {}), dimColor: item.kind === 'notice', children: [item.kind === 'warning' ? '⚠ ' : '· ', item.text] }, entry.key));
|
|
631
577
|
}), activeStreamVisible && activeThinking ? (_jsx(ThinkingBlock, { text: activeThinking, active: true, expanded: detailed, screenReader: screenReader })) : activeStreamVisible && activeText ? (_jsxs(Box, { marginTop: 1, children: [screenReader ? (_jsx(Text, { children: "Praxis: " })) : (_jsx(Text, { color: palette.accent, children: "\u2733 " })), screenReader ? (_jsx(MarkdownText, { text: activeText })) : (_jsx(ActiveStreamText, { text: activeText }))] })) : null] }));
|
|
632
578
|
}
|
|
633
579
|
export function DiffDashboard({ snapshots, sourceIndex, selectedIndex, viewingFile, scrollOffset, width, screenReader, }) {
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { ModelToolCall } from '../../core/runtime.js';
|
|
2
|
+
export type TranscriptItem = {
|
|
3
|
+
kind: 'user' | 'assistant' | 'notice' | 'warning';
|
|
4
|
+
text: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'local-result';
|
|
7
|
+
text: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'thinking';
|
|
10
|
+
text: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'compact';
|
|
13
|
+
summary: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'context';
|
|
16
|
+
usedTokens: number;
|
|
17
|
+
contextWindowTokens: number;
|
|
18
|
+
model?: string;
|
|
19
|
+
skills: readonly {
|
|
20
|
+
name: string;
|
|
21
|
+
tokens: number;
|
|
22
|
+
}[];
|
|
23
|
+
memoryFiles: readonly {
|
|
24
|
+
path: string;
|
|
25
|
+
tokens: number;
|
|
26
|
+
}[];
|
|
27
|
+
} | {
|
|
28
|
+
kind: 'tool';
|
|
29
|
+
call: ModelToolCall;
|
|
30
|
+
detail: string;
|
|
31
|
+
} | {
|
|
32
|
+
kind: 'tool-result';
|
|
33
|
+
callId: string;
|
|
34
|
+
text: string;
|
|
35
|
+
isError: boolean;
|
|
36
|
+
} | {
|
|
37
|
+
kind: 'shell';
|
|
38
|
+
callId: string;
|
|
39
|
+
command: string;
|
|
40
|
+
} | {
|
|
41
|
+
kind: 'shell-result';
|
|
42
|
+
callId: string;
|
|
43
|
+
stdout: string;
|
|
44
|
+
stderr: string;
|
|
45
|
+
isError: boolean;
|
|
46
|
+
};
|
|
47
|
+
export type TranscriptPresentationMode = 'normal' | 'audit' | 'screen-reader';
|
|
48
|
+
type ToolItem = Extract<TranscriptItem, {
|
|
49
|
+
kind: 'tool';
|
|
50
|
+
}>;
|
|
51
|
+
type ToolResultItem = Extract<TranscriptItem, {
|
|
52
|
+
kind: 'tool-result';
|
|
53
|
+
}>;
|
|
54
|
+
type ShellItem = Extract<TranscriptItem, {
|
|
55
|
+
kind: 'shell';
|
|
56
|
+
}>;
|
|
57
|
+
type ShellResultItem = Extract<TranscriptItem, {
|
|
58
|
+
kind: 'shell-result';
|
|
59
|
+
}>;
|
|
60
|
+
export type TranscriptPresentationEntry = {
|
|
61
|
+
kind: 'item';
|
|
62
|
+
key: string;
|
|
63
|
+
item: Exclude<TranscriptItem, ToolItem | ToolResultItem | ShellItem | ShellResultItem>;
|
|
64
|
+
} | {
|
|
65
|
+
kind: 'tool';
|
|
66
|
+
key: string;
|
|
67
|
+
item: ToolItem;
|
|
68
|
+
result?: ToolResultItem;
|
|
69
|
+
} | {
|
|
70
|
+
kind: 'orphan-tool-result';
|
|
71
|
+
key: string;
|
|
72
|
+
item: ToolResultItem;
|
|
73
|
+
} | {
|
|
74
|
+
kind: 'shell';
|
|
75
|
+
key: string;
|
|
76
|
+
item: ShellItem;
|
|
77
|
+
result?: ShellResultItem;
|
|
78
|
+
} | {
|
|
79
|
+
kind: 'orphan-shell-result';
|
|
80
|
+
key: string;
|
|
81
|
+
item: ShellResultItem;
|
|
82
|
+
} | {
|
|
83
|
+
kind: 'read-summary';
|
|
84
|
+
key: string;
|
|
85
|
+
count: number;
|
|
86
|
+
};
|
|
87
|
+
export declare function projectTranscriptPresentation(items: readonly TranscriptItem[], mode: TranscriptPresentationMode): readonly TranscriptPresentationEntry[];
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=transcript-presentation.d.ts.map
|