tc043 commited on
Commit
20eda77
·
1 Parent(s): 44d6800

feat: improve task generation logic with line-by-line parsing, refined system prompts, and enhanced state tracking for raw task history

Browse files
Files changed (1) hide show
  1. app.py +57 -10
app.py CHANGED
@@ -111,18 +111,33 @@ async def generate_atomic_task(goal: str, previous_failures: int, history: list
111
  temperature=0.3,
112
  stop=["\n", "<extra_id_1>"]
113
  )
114
- content = response['choices'][0]['text'].strip()
115
 
116
- # Check if output is empty, repeats prompt headers, or does not represent a task step
117
- is_invalid = (
118
- not content or
119
- any(header in content for header in ["Goal:", "Completed Tasks:", "Failures:", "Output the NEXT step", "<extra_id"])
120
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  if is_invalid:
123
- print(f"NEMOTRON OUTPUT INVALID ('{content}'). FALLING BACK TO MINICPM...", flush=True)
124
  messages = [
125
- {"role": "system", "content": "You are a cognitive pacemaker. Break down goals into extremely tiny, atomic physical actions under 8 words. Return ONLY the single physical next step."},
126
  {"role": "user", "content": f"Goal: {goal}\nCompleted Tasks: {history_str}\nFailures: {previous_failures}\nOutput the NEXT step."}
127
  ]
128
  fallback_res = await run_blocking(
@@ -153,8 +168,33 @@ async def apply_activation_style(task: str, style="direct") -> str:
153
  if style == "direct":
154
  return f"{task.capitalize()}."
155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  messages = [
157
- {"role": "system", "content": f"You are a helpful assistant. Rewrite the following task into a {style} tone. Only output the final task text and nothing else."},
158
  {"role": "user", "content": f"Task: {task}"}
159
  ]
160
  response = await run_blocking(
@@ -196,8 +236,10 @@ async def websocket_endpoint(websocket: WebSocket):
196
  "goal": "",
197
  "style": "direct",
198
  "current_task": "",
 
199
  "too_hard_count": 0,
200
  "history": [],
 
201
  "trace": [],
202
  }
203
 
@@ -213,8 +255,10 @@ async def websocket_endpoint(websocket: WebSocket):
213
  state["goal"] = payload.get("goal")
214
  state["style"] = payload.get("style", "direct")
215
  state["current_task"] = ""
 
216
  state["too_hard_count"] = 0
217
  state["history"] = []
 
218
  state["trace"] = [{"event": "start", "goal": state["goal"], "style": state["style"]}]
219
 
220
  elif action == "too_hard":
@@ -229,6 +273,8 @@ async def websocket_endpoint(websocket: WebSocket):
229
  state["too_hard_count"] = 0
230
  if payload.get("last_task"):
231
  state["history"].append(payload.get("last_task"))
 
 
232
  state["trace"].append({"event": "done", "task": payload.get("last_task")})
233
 
234
  # HARD CIRCUIT BREAKER
@@ -250,11 +296,12 @@ async def websocket_endpoint(websocket: WebSocket):
250
  raw_task = await generate_atomic_task(
251
  state["goal"],
252
  state["too_hard_count"],
253
- history=state["history"],
254
  rejected_task=rejected_task,
255
  )
256
  styled_task = await apply_activation_style(raw_task, state["style"])
257
  state["current_task"] = styled_task
 
258
  state["trace"].append({
259
  "event": "generated_step",
260
  "raw_task": raw_task,
 
111
  temperature=0.3,
112
  stop=["\n", "<extra_id_1>"]
113
  )
114
+ raw_content = response['choices'][0]['text'].strip()
115
 
116
+ # Parse content line-by-line to extract the actual task step
117
+ content = ""
118
+ lines = [line.strip() for line in raw_content.split("\n")]
119
+ for line in lines:
120
+ if not line:
121
+ continue
122
+ has_header = any(
123
+ header in line for header in [
124
+ "Goal:", "Completed Tasks:", "Failures:", "Output the NEXT step",
125
+ "<extra_id", "System", "Assistant", "User"
126
+ ]
127
+ )
128
+ if not has_header:
129
+ words = line.split()
130
+ if 1 <= len(words) <= 12:
131
+ content = line
132
+ break
133
+
134
+ # Check if output is empty
135
+ is_invalid = not content
136
 
137
  if is_invalid:
138
+ print(f"NEMOTRON OUTPUT INVALID ('{raw_content}'). FALLING BACK TO MINICPM...", flush=True)
139
  messages = [
140
+ {"role": "system", "content": "You are a cognitive pacemaker. Focus strictly on the physical goal and break it down into an extremely tiny, atomic physical action under 8 words. Ignore mental blocks or feelings of being stuck and output ONLY the single physical action step."},
141
  {"role": "user", "content": f"Goal: {goal}\nCompleted Tasks: {history_str}\nFailures: {previous_failures}\nOutput the NEXT step."}
142
  ]
143
  fallback_res = await run_blocking(
 
168
  if style == "direct":
169
  return f"{task.capitalize()}."
170
 
171
+ if style == "encouraging":
172
+ system_prompt = (
173
+ "You are a cognitive pacemaker. Rewrite the given task into an encouraging, supportive tone.\n"
174
+ "RULES:\n"
175
+ "1. Keep it as an action/command the user MUST do now. Start or end with an encouraging phrase like 'You got this!', 'Let's do it!', or 'Go ahead and...'.\n"
176
+ "2. Do NOT write in the past tense, do NOT congratulate the user, and do NOT treat the task as already completed.\n"
177
+ "3. Keep it brief (under 12 words) and output ONLY the final rewritten task."
178
+ )
179
+ elif style == "calm":
180
+ system_prompt = (
181
+ "You are a cognitive pacemaker. Rewrite the given task into a calm, gentle tone.\n"
182
+ "RULES:\n"
183
+ "1. Keep it as an action/command. Use gentle prefixes like 'When you are ready, ...' or 'Take your time and ...'.\n"
184
+ "2. Do NOT write in the past tense and do NOT congratulate the user.\n"
185
+ "3. Keep it brief (under 12 words) and output ONLY the final rewritten task."
186
+ )
187
+ else:
188
+ system_prompt = (
189
+ f"You are a cognitive pacemaker. Rewrite the given task into a {style} tone.\n"
190
+ "RULES:\n"
191
+ "1. Keep it as an action/command the user MUST do now.\n"
192
+ "2. Do NOT write in the past tense, do NOT congratulate the user, and do NOT treat the task as already completed.\n"
193
+ "3. Keep it brief (under 12 words) and output ONLY the final rewritten task."
194
+ )
195
+
196
  messages = [
197
+ {"role": "system", "content": system_prompt},
198
  {"role": "user", "content": f"Task: {task}"}
199
  ]
200
  response = await run_blocking(
 
236
  "goal": "",
237
  "style": "direct",
238
  "current_task": "",
239
+ "current_raw_task": "",
240
  "too_hard_count": 0,
241
  "history": [],
242
+ "raw_history": [],
243
  "trace": [],
244
  }
245
 
 
255
  state["goal"] = payload.get("goal")
256
  state["style"] = payload.get("style", "direct")
257
  state["current_task"] = ""
258
+ state["current_raw_task"] = ""
259
  state["too_hard_count"] = 0
260
  state["history"] = []
261
+ state["raw_history"] = []
262
  state["trace"] = [{"event": "start", "goal": state["goal"], "style": state["style"]}]
263
 
264
  elif action == "too_hard":
 
273
  state["too_hard_count"] = 0
274
  if payload.get("last_task"):
275
  state["history"].append(payload.get("last_task"))
276
+ raw_task_done = state.get("current_raw_task") or payload.get("last_task")
277
+ state["raw_history"].append(raw_task_done)
278
  state["trace"].append({"event": "done", "task": payload.get("last_task")})
279
 
280
  # HARD CIRCUIT BREAKER
 
296
  raw_task = await generate_atomic_task(
297
  state["goal"],
298
  state["too_hard_count"],
299
+ history=state["raw_history"],
300
  rejected_task=rejected_task,
301
  )
302
  styled_task = await apply_activation_style(raw_task, state["style"])
303
  state["current_task"] = styled_task
304
+ state["current_raw_task"] = raw_task
305
  state["trace"].append({
306
  "event": "generated_step",
307
  "raw_task": raw_task,