cliclaw 1.0.16 → 1.0.17
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/package.json +1 -1
- package/src/agents/codex.ts +27 -6
package/package.json
CHANGED
package/src/agents/codex.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'child_process'
|
|
2
|
-
import type { Session } from '../storage'
|
|
2
|
+
import type { Session, Message } from '../storage'
|
|
3
3
|
import type { TokenUsage } from './claude'
|
|
4
4
|
|
|
5
5
|
const HOME = process.env.HOME || process.env.USERPROFILE || '/root'
|
|
@@ -34,7 +34,22 @@ function extractTextFromObj(obj: any): string | null {
|
|
|
34
34
|
return null
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function
|
|
37
|
+
function buildPrompt(history: Message[], userMessage: string): string {
|
|
38
|
+
// history already contains the current user message as the last item (added before askCodex)
|
|
39
|
+
const prior = history.slice(0, -1).slice(-20) // up to last 20 prior messages
|
|
40
|
+
if (prior.length === 0) return userMessage
|
|
41
|
+
const lines = prior.map(m => {
|
|
42
|
+
let content = m.content
|
|
43
|
+
// Strip usage stats suffix (e.g. "\n`📊 ↑1234 ↓56`")
|
|
44
|
+
const usageIdx = content.lastIndexOf('\n`📊')
|
|
45
|
+
if (usageIdx > 0) content = content.slice(0, usageIdx)
|
|
46
|
+
if (content.length > 600) content = content.slice(0, 600) + '…'
|
|
47
|
+
return `${m.role === 'user' ? 'User' : 'Assistant'}: ${content}`
|
|
48
|
+
})
|
|
49
|
+
return `<conversation_history>\n${lines.join('\n')}\n</conversation_history>\n\nUser: ${userMessage}`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function spawnCodex(args: string[], stdinText?: string): Promise<{ text: string; threadId: string | null; usage?: TokenUsage }> {
|
|
38
53
|
return new Promise((resolve, reject) => {
|
|
39
54
|
let stdout = ''
|
|
40
55
|
let stderr = ''
|
|
@@ -44,8 +59,12 @@ function spawnCodex(args: string[]): Promise<{ text: string; threadId: string |
|
|
|
44
59
|
cwd: process.cwd(),
|
|
45
60
|
shell: isWin,
|
|
46
61
|
windowsHide: true,
|
|
47
|
-
|
|
62
|
+
// Use pipe for stdin when we have text to send; otherwise ignore to prevent PM2 hang
|
|
63
|
+
stdio: [stdinText != null ? 'pipe' : 'ignore', 'pipe', 'pipe'],
|
|
48
64
|
})
|
|
65
|
+
if (stdinText != null) {
|
|
66
|
+
proc.stdin!.end(stdinText, 'utf8')
|
|
67
|
+
}
|
|
49
68
|
proc.stdout.on('data', (d: Buffer) => { stdout += d.toString() })
|
|
50
69
|
proc.stderr.on('data', (d: Buffer) => {
|
|
51
70
|
const s = d.toString().trim()
|
|
@@ -101,9 +120,11 @@ export async function askCodex(
|
|
|
101
120
|
onNewThreadId?: (id: string) => void
|
|
102
121
|
): Promise<{ text: string; usage?: TokenUsage }> {
|
|
103
122
|
try {
|
|
104
|
-
//
|
|
105
|
-
const
|
|
106
|
-
|
|
123
|
+
// Build full prompt with conversation history, send via stdin (avoids Windows arg escaping issues)
|
|
124
|
+
const prompt = buildPrompt(session.history, userMessage)
|
|
125
|
+
// `-` tells codex exec to read PROMPT from stdin
|
|
126
|
+
const args = ['exec', '--dangerously-bypass-approvals-and-sandbox', '--skip-git-repo-check', '--json', '-']
|
|
127
|
+
const { text, threadId, usage } = await spawnCodex(args, prompt)
|
|
107
128
|
if (threadId && !session.codexThreadId) onNewThreadId?.(threadId)
|
|
108
129
|
return { text, usage }
|
|
109
130
|
} catch (err: any) {
|