bep40 commited on
Commit
cd124c3
·
verified ·
1 Parent(s): 87e7b37

V14: Simple ASCII text - build first, add Vietnamese later

Browse files
Files changed (1) hide show
  1. patch_auto_continue_v14.py +166 -0
patch_auto_continue_v14.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """V14: Auto-continue. Use ASCII-only text for reliable build."""
2
+
3
+ import os, sys
4
+
5
+ ROOT = "/source/frontend/src"
6
+
7
+ FILES = {
8
+ "events.ts": ROOT + "/types/events.ts",
9
+ "sse.ts": ROOT + "/lib/sse-chat-transport.ts",
10
+ "hook.ts": ROOT + "/hooks/useAgentChat.ts",
11
+ "input.tsx": ROOT + "/components/Chat/ChatInput.tsx",
12
+ "sess.tsx": ROOT + "/components/SessionChat.tsx",
13
+ "agent.py": "/app/agent/core/agent_loop.py",
14
+ }
15
+
16
+ # 1. events.ts
17
+ c = open(FILES["events.ts"]).read()
18
+ if "'task_incomplete'" not in c:
19
+ c = c.replace(" | 'interrupted'", " | 'interrupted'\n | 'task_incomplete'")
20
+ open(FILES["events.ts"], 'w').write(c)
21
+ print("OK: events.ts")
22
+
23
+ # 2. sse.ts
24
+ c = open(FILES["sse.ts"]).read()
25
+ if "case 'task_incomplete'" not in c:
26
+ block = """ case 'task_incomplete':
27
+ (sideChannel as any).onTaskIncomplete(
28
+ (event.data?.incomplete_plan as Array<{ id: string; content: string; status: string }>) || [],
29
+ );
30
+ break;
31
+
32
+ default:"""
33
+ c = c.replace("\n default:", "\n" + block)
34
+ open(FILES["sse.ts"], 'w').write(c)
35
+ print("OK: sse.ts")
36
+
37
+ # 3. hook.ts - useAgentChat.ts
38
+ c = open(FILES["hook.ts"]).read()
39
+
40
+ # useState import
41
+ if "useState" not in c:
42
+ c = c.replace(
43
+ "import { useCallback, useEffect, useMemo, useRef } from 'react';",
44
+ "import { useCallback, useEffect, useMemo, useRef, useState } from 'react';"
45
+ )
46
+
47
+ # State after callbacksRef
48
+ if "_showAc" not in c:
49
+ state_block = (
50
+ " // Auto-continue state\n"
51
+ " const [_showAc, _setShowAc] = useState(false);\n"
52
+ " const _acRef = useRef<Array<{ id: string; content: string; status: string }>>([]);\n"
53
+ )
54
+ c = c.replace(
55
+ "callbacksRef.current = { onReady, onError, onSessionDead };",
56
+ "callbacksRef.current = { onReady, onError, onSessionDead };\n" + state_block
57
+ )
58
+
59
+ # Handler in onSessionUpdate
60
+ if "ac_plan" not in c:
61
+ handler = (
62
+ " // Auto-continue check\n"
63
+ " if ((data as any).ac_plan) {\n"
64
+ " _acRef.current = (data as any).ac_plan;\n"
65
+ " _setShowAc(true);\n"
66
+ " return;\n"
67
+ " }\n"
68
+ )
69
+ c = c.replace("onSessionUpdate: (data) => {", "onSessionUpdate: (data) => {\n" + handler)
70
+
71
+ # Cancel + effect before return
72
+ if "_acCancel" not in c:
73
+ cancel = " const _acCancel = useCallback(() => { _setShowAc(false); }, []);\n"
74
+ effect = (
75
+ " useEffect(() => {\n"
76
+ " if (!_showAc) return;\n"
77
+ " const plan = _acRef.current;\n"
78
+ " const timer = setTimeout(() => {\n"
79
+ " const s = chatActionsRef.current.setMessages;\n"
80
+ " const m = chatActionsRef.current.messages;\n"
81
+ " if (s && plan.length > 0) {\n"
82
+ " const t = plan.map((i: { content: string }) => '- ' + i.content).join('\\\\n');\n"
83
+ " const nu = { id: 'ac-'+Date.now(), role: 'user' as const, parts: [{ type: 'text' as const, text: '[TIEP TUC] Task chua hoan thanh:\\\\n' + t }], content: '' };\n"
84
+ " s([...m, nu]);\n"
85
+ " }\n"
86
+ " _setShowAc(false);\n"
87
+ " }, 10000);\n"
88
+ " return () => clearTimeout(timer);\n"
89
+ " }, [_showAc]);\n\n"
90
+ )
91
+ c = c.replace(
92
+ " return {\n messages: chat.messages,",
93
+ cancel + effect + " return {\n messages: chat.messages,"
94
+ )
95
+
96
+ # Return values
97
+ if "_showAc," not in c:
98
+ c = c.replace("refreshMessages,\n };", "refreshMessages,\n _showAc,\n _acCancel,\n };")
99
+
100
+ open(FILES["hook.ts"], 'w').write(c)
101
+ print("OK: useAgentChat.ts")
102
+
103
+ # 4. input.tsx - ChatInput.tsx
104
+ c = open(FILES["input.tsx"]).read()
105
+
106
+ if "Button" not in c:
107
+ # Match the exact MUI import block
108
+ c = c.replace("import {\n Alert,\n Box,\n TextField,\n IconButton,\n CircularProgress,\n Typography,\n Menu,\n MenuItem,\n ListItemIcon,\n ListItemText,\n Chip,\n LinearProgress,\n Snackbar,\n Tooltip,\n} from '@mui/material';",
109
+ "import {\n Alert,\n Box,\n TextField,\n IconButton,\n CircularProgress,\n Typography,\n Menu,\n MenuItem,\n ListItemIcon,\n ListItemText,\n Chip,\n LinearProgress,\n Snackbar,\n Tooltip,\n Button,\n} from '@mui/material';")
110
+
111
+ if "_showAc" not in c:
112
+ c = c.replace("placeholder?: string;", "placeholder?: string;\n _showAc?: boolean;\n _acCancel?: () => void;")
113
+ c = c.replace("placeholder = 'Ask anything...' }: ChatInputProps) {",
114
+ "placeholder = 'Ask anything...', _showAc = false, _acCancel }: ChatInputProps) {")
115
+
116
+ if "TAM_DUNG" not in c:
117
+ btn = (
118
+ " {_showAc && _acCancel && (\n"
119
+ " <Box sx={{ display: 'flex', justifyContent: 'center', mt: 1 }}>\n"
120
+ " <Button variant=\"outlined\" size=\"small\" onClick={_acCancel}\n"
121
+ " sx={{ textTransform: 'none', fontSize: '0.7rem', opacity: 0.7, '&:hover': { opacity: 1 } }}>\n"
122
+ " TAM_DUNG_TU_DONG_TIEP_TUC\n"
123
+ " </Button>\n"
124
+ " </Box>\n"
125
+ " )}\n"
126
+ )
127
+ c = c.replace("<JobsUpgradeDialog", btn + " <JobsUpgradeDialog")
128
+
129
+ open(FILES["input.tsx"], 'w').write(c)
130
+ print("OK: ChatInput.tsx")
131
+
132
+ # 5. sess.tsx - SessionChat.tsx
133
+ if os.path.exists(FILES["sess.tsx"]):
134
+ c = open(FILES["sess.tsx"]).read()
135
+ if "_showAc" not in c:
136
+ c = c.replace("<ChatInput ", "<ChatInput _showAc={_showAc} _acCancel={_acCancel} ")
137
+ open(FILES["sess.tsx"], 'w').write(c)
138
+ print("OK: SessionChat.tsx")
139
+
140
+ # 6. agent.py
141
+ if os.path.exists(FILES["agent.py"]):
142
+ c = open(FILES["agent.py"]).read()
143
+
144
+ if "_unfinished_plan" not in c:
145
+ fn = "\n\ndef _unfinished_plan(s):\n p = getattr(s, 'current_plan', None) or []\n return [it for it in p if it.get('status') in ('pending', 'in_progress')]\n"
146
+ c = c.replace("class Handlers:", fn + "\n\nclass Handlers:")
147
+
148
+ if "ac_plan" not in c:
149
+ check = (
150
+ "\n if not llm_result.tool_calls_acc and llm_result.content:\n"
151
+ " unfinished = _unfinished_plan(session)\n"
152
+ " if unfinished:\n"
153
+ " await session.send_event(Event(event_type='session_update', data={\n"
154
+ " 'ac_plan': unfinished,\n"
155
+ " }))\n"
156
+ )
157
+ marker = " # -- End of turn --"
158
+ if marker in c:
159
+ c = c.replace(marker, check + marker)
160
+
161
+ open(FILES["agent.py"], 'w').write(c)
162
+ print("OK: agent_loop.py")
163
+ else:
164
+ print("SKIP: agent_loop.py")
165
+
166
+ print("\nDONE: V14")