Skip to content

Commit d7b0883

Browse files
authored
Fix_chat_ui (#4)
* adding details to agents.md * checking * fixing app.tsx * feat: Add conversation ID and status tracking to chat messages - Enhanced `useChatExecution` hook to support conversation IDs and message statuses. - Updated tests to verify streaming messages include conversation IDs. - Modified `useChatPersistence` to handle new message properties. - Improved `ClaudeStreamParser` to manage tool calls and results more effectively. - Introduced `generateId` utility for unique ID generation. - Added default CLI agent selection and maximum chat history settings in the UI. - Implemented tests for default agent selection and chat history limits. - Refactored settings context to include default CLI agent and max chat history.
1 parent 675756f commit d7b0883

51 files changed

Lines changed: 2079 additions & 462 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ dist-ssr
2323
*.njsproj
2424
*.sln
2525
*.sw?
26+
PRD/
27+
TDD/
2628

2729
# Environment variables
2830
.env

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44

55
Every agent working on this Commander project MUST follow these standards. No exceptions.
66

7+
<<<<<<< HEAD
78
We use bun run tauri dev to run the app.
89

910
You always work on features that are configurable via the Settings Panel in the app. Every feature must be toggleable or adjustable through user preferences.
1011
Before you write any code, you will write the PRD and save in the docs/ directory.
1112

1213
You write the TDD and then write the feature implementation.
14+
=======
15+
Every prompt or request by the user you will create a PRD and store it in the `PRD/` folder with a filename that matches the feature name. You will then follow the TDD and architecture patterns below to implement the feature.
16+
>>>>>>> f5183e6 (fixing the ui for chat to be default)
1317
1418
## Architecture Pattern - STRICT COMPLIANCE
1519

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Product Requirements Document: Chat Default View on Project Select
2+
3+
## Overview
4+
- **Problem:** When a user selects or opens a project, the UI shows the Code tab by default, forcing extra interaction to reach the chat workspace.
5+
- **Outcome:** Selecting, opening, or creating a project must land the user directly in the Chat tab so conversational workflows remain primary.
6+
- **Success Metrics:** Zero additional clicks required to reach Chat immediately after any project activation flow.
7+
8+
## Requirements
9+
- Switching to any project (recents list, open dialog, menu, CLI-start, post-create) must activate the Chat tab by default.
10+
- Returning to Welcome must *not* alter the chat-first preference when re-entering a project.
11+
- Active tab state persists within a project session; manual tab switches must still function.
12+
- No regressions to breadcrumb, sidebar, or history functionality.
13+
14+
## Constraints & Assumptions
15+
- Applies only once a project becomes active; welcome screen remains unchanged.
16+
- Tabs component already supports controlled `value`; only state transitions need adjusting.
17+
- No backend changes required; behavior is purely frontend state management.
18+
19+
## User Journey
20+
1. User launches Commander, opens an existing project → Chat tab visible immediately.
21+
2. User selects a recent project from welcome list → Chat tab already active.
22+
3. User creates or clones a project → Chat tab shows after project loads.
23+
4. User reopens Commander from CLI project flag → Chat tab displays on load.
24+
25+
## Open Questions
26+
- None identified.
27+
28+
## Test Plan
29+
- Add a UI test verifying that selecting a recent project results in the Chat tab trigger being active.
30+
- Ensure regression tests confirming welcome recents rendering continue to pass.
31+

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"dependencies": {
1616
"@openai/codex": "^0.44.0",
17-
"@openai/codex-sdk": "^0.44.0",
17+
"@openai/codex-sdk": "^0.45.0",
1818
"@phosphor-icons/react": "^2.1.10",
1919
"@radix-ui/react-accordion": "^1.2.12",
2020
"@radix-ui/react-alert-dialog": "^1.1.15",
@@ -30,6 +30,7 @@
3030
"@radix-ui/react-separator": "^1.1.7",
3131
"@radix-ui/react-slot": "^1.2.3",
3232
"@radix-ui/react-switch": "^1.2.6",
33+
"@radix-ui/react-tabs": "^1.1.13",
3334
"@radix-ui/react-toggle": "^1.1.10",
3435
"@radix-ui/react-tooltip": "^1.2.8",
3536
"@radix-ui/react-use-controllable-state": "^1.2.2",

scripts/codex-sdk-core.mjs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { pathToFileURL } from 'url'
2+
import fs from 'fs'
3+
4+
export async function runCodex(options = {}, io = defaultIO) {
5+
const {
6+
sessionId,
7+
prompt = '',
8+
workingDirectory,
9+
sandboxMode,
10+
model,
11+
skipGitRepoCheck,
12+
} = options
13+
14+
let CodexModule
15+
const distPath = process.env.CODEX_SDK_DIST_PATH
16+
if (distPath && fs.existsSync(distPath)) {
17+
CodexModule = await import(pathToFileURL(distPath).href)
18+
} else {
19+
CodexModule = await import('@openai/codex-sdk')
20+
}
21+
const { Codex } = CodexModule
22+
23+
const codexOptions = workingDirectory ? { workingDirectory } : {}
24+
const codex = new Codex(codexOptions)
25+
26+
const threadOptions = {
27+
...(model ? { model } : {}),
28+
...(sandboxMode ? { sandboxMode } : {}),
29+
...(workingDirectory ? { workingDirectory } : {}),
30+
skipGitRepoCheck: skipGitRepoCheck !== false,
31+
}
32+
33+
const thread = codex.startThread(threadOptions)
34+
35+
try {
36+
const { events } = await thread.runStreamed(prompt)
37+
for await (const event of events) {
38+
await io.write(
39+
JSON.stringify({
40+
sessionId,
41+
content: JSON.stringify(event),
42+
finished: false,
43+
})
44+
)
45+
}
46+
47+
await io.write(
48+
JSON.stringify({
49+
sessionId,
50+
content: '',
51+
finished: true,
52+
})
53+
)
54+
} catch (error) {
55+
const message = error instanceof Error ? error.message : String(error)
56+
if (process.env.DEBUG_CodexSDK === '1') {
57+
console.error('[codex-sdk-core] error:', message)
58+
if (error && error.stack) {
59+
console.error(error.stack)
60+
}
61+
}
62+
const payload = JSON.stringify({ sessionId, error: message, finished: true })
63+
if (io.writeError) {
64+
await io.writeError(payload)
65+
} else {
66+
await io.write(payload)
67+
}
68+
}
69+
}
70+
71+
export async function readStdin() {
72+
const chunks = []
73+
for await (const chunk of process.stdin) {
74+
chunks.push(chunk)
75+
}
76+
if (!chunks.length) return ''
77+
return Buffer.concat(chunks.map((c) => (typeof c === 'string' ? Buffer.from(c) : c))).toString('utf8')
78+
}
79+
80+
export const defaultIO = {
81+
write: async (msg) => {
82+
process.stdout.write(msg + '\n')
83+
},
84+
writeError: async (msg) => {
85+
process.stderr.write(msg + '\n')
86+
},
87+
}

scripts/codex-sdk-runner.mjs

Lines changed: 3 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,8 @@
11
#!/usr/bin/env node
22
import fs from 'fs'
3-
import { pathToFileURL, fileURLToPath } from 'url'
4-
5-
export async function runCodex(options = {}, io = defaultIO) {
6-
const {
7-
sessionId,
8-
prompt = '',
9-
workingDirectory,
10-
sandboxMode,
11-
model,
12-
skipGitRepoCheck,
13-
} = options
14-
15-
let CodexModule
16-
const distPath = process.env.CODEX_SDK_DIST_PATH
17-
if (distPath && fs.existsSync(distPath)) {
18-
CodexModule = await import(pathToFileURL(distPath).href)
19-
} else {
20-
CodexModule = await import('@openai/codex-sdk')
21-
}
22-
const { Codex } = CodexModule
23-
24-
const codexOptions = workingDirectory ? { workingDirectory } : {}
25-
const codex = new Codex(codexOptions)
26-
27-
const threadOptions = {
28-
...(model ? { model } : {}),
29-
...(sandboxMode ? { sandboxMode } : {}),
30-
...(workingDirectory ? { workingDirectory } : {}),
31-
skipGitRepoCheck: skipGitRepoCheck !== false,
32-
}
33-
34-
const thread = codex.startThread(threadOptions)
35-
36-
try {
37-
const { events } = await thread.runStreamed(prompt)
38-
for await (const event of events) {
39-
await io.write(
40-
JSON.stringify({
41-
sessionId,
42-
content: JSON.stringify(event),
43-
finished: false,
44-
})
45-
)
46-
}
47-
48-
await io.write(
49-
JSON.stringify({
50-
sessionId,
51-
content: '',
52-
finished: true,
53-
})
54-
)
55-
} catch (error) {
56-
const message = error instanceof Error ? error.message : String(error)
57-
const payload = JSON.stringify({ sessionId, error: message, finished: true })
58-
if (io.writeError) {
59-
await io.writeError(payload)
60-
} else {
61-
await io.write(payload)
62-
}
63-
}
64-
}
65-
66-
async function readStdin() {
67-
const chunks = []
68-
for await (const chunk of process.stdin) {
69-
chunks.push(chunk)
70-
}
71-
if (!chunks.length) return ''
72-
return Buffer.concat(chunks.map((c) => (typeof c === 'string' ? Buffer.from(c) : c))).toString('utf8')
73-
}
3+
import { fileURLToPath } from 'url'
4+
import { runCodex, readStdin } from './codex-sdk-core.mjs'
5+
export { runCodex } from './codex-sdk-core.mjs'
746

757
async function main() {
768
const stdin = await readStdin()
@@ -85,15 +17,6 @@ async function main() {
8517
await runCodex(payload)
8618
}
8719

88-
const defaultIO = {
89-
write: async (msg) => {
90-
process.stdout.write(msg + '\n')
91-
},
92-
writeError: async (msg) => {
93-
process.stderr.write(msg + '\n')
94-
},
95-
}
96-
9720
// Check if this script is being run directly
9821
// Use fs.realpathSync to resolve symlinks (like /var -> /private/var on macOS)
9922
const scriptPath = process.argv[1] ? fs.realpathSync(process.argv[1]) : null

src-tauri/src/commands/chat_migration_commands.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ pub async fn save_enhanced_chat_message(
142142
content,
143143
timestamp: chrono::Utc::now().timestamp(),
144144
agent: Some(agent),
145+
conversation_id: None,
146+
status: None,
147+
steps: None,
145148
};
146149

147150
// Load existing legacy messages and append

0 commit comments

Comments
 (0)