ccm commited on
Commit
0b902e8
·
1 Parent(s): 559ed45

Moving more things over into agent_server

Browse files
Files changed (2) hide show
  1. agent_server/formatting_reasoning.py +98 -0
  2. proxy.py +2 -96
agent_server/formatting_reasoning.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import re
3
+ import typing
4
+
5
+ from agent_server.sanitizing_think_tags import scrub_think_tags
6
+
7
+
8
+ def _format_reasoning_chunk(text: str, tag: str, idx: int) -> str:
9
+ """
10
+ Lightweight formatter for reasoning stream. Avoid huge code fences;
11
+ make it readable and incremental. Also filters out ASCII/box-drawing noise.
12
+ """
13
+ text = scrub_think_tags(text).rstrip("\n")
14
+ if not text:
15
+ return ""
16
+ noisy_prefixes = (
17
+ "OpenAIServerModel",
18
+ "Output message of the LLM",
19
+ "─ Executing parsed code",
20
+ "New run",
21
+ "╭",
22
+ "╰",
23
+ "│",
24
+ "━",
25
+ "─",
26
+ )
27
+ stripped = text.strip()
28
+ if not stripped:
29
+ return ""
30
+ # Lines made mostly of box drawing/separators
31
+ if all(ch in " ─━╭╮╰╯│═·—-_=+•" for ch in stripped):
32
+ return ""
33
+ if any(stripped.startswith(p) for p in noisy_prefixes):
34
+ return ""
35
+ # Excessively long lines with little signal (no alphanumerics)
36
+ if len(stripped) > 240 and not re.search(r"[A-Za-z0-9]{3,}", stripped):
37
+ return ""
38
+ # No tag/idx prefix; add a trailing blank line for readability in markdown
39
+ return f"{stripped}\n\n"
40
+
41
+
42
+ def _extract_final_text(item: typing.Any) -> typing.Optional[str]:
43
+ if isinstance(item, dict) and ("__stdout__" in item or "__step__" in item):
44
+ return None
45
+ if isinstance(item, (bytes, bytearray)):
46
+ try:
47
+ item = item.decode("utf-8", errors="ignore")
48
+ except Exception:
49
+ item = str(item)
50
+ if isinstance(item, str):
51
+ s = scrub_think_tags(item.strip())
52
+ return s or None
53
+ # If it's a step-like object with an 'output' attribute, use that
54
+ try:
55
+ if not isinstance(item, (dict, list, bytes, bytearray)):
56
+ out = getattr(item, "output", None)
57
+ if out is not None:
58
+ s = scrub_think_tags(str(out)).strip()
59
+ if s:
60
+ return s
61
+ except Exception:
62
+ pass
63
+ if isinstance(item, dict):
64
+ for key in ("content", "text", "message", "output", "final", "answer"):
65
+ if key in item:
66
+ val = item[key]
67
+ if isinstance(val, (dict, list)):
68
+ try:
69
+ return scrub_think_tags(json.dumps(val, ensure_ascii=False))
70
+ except Exception:
71
+ return scrub_think_tags(str(val))
72
+ if isinstance(val, (bytes, bytearray)):
73
+ try:
74
+ val = val.decode("utf-8", errors="ignore")
75
+ except Exception:
76
+ val = str(val)
77
+ s = scrub_think_tags(str(val).strip())
78
+ return s or None
79
+ try:
80
+ return scrub_think_tags(json.dumps(item, ensure_ascii=False))
81
+ except Exception:
82
+ return scrub_think_tags(str(item))
83
+ try:
84
+ return scrub_think_tags(str(item))
85
+ except Exception:
86
+ return None
87
+
88
+
89
+ _FINAL_RE = re.compile(r"(?:^|\\b)Final\\s+answer:\\s*(.+)$", flags=re.IGNORECASE)
90
+
91
+
92
+ def _maybe_parse_final_from_stdout(line: str) -> typing.Optional[str]:
93
+ if not isinstance(line, str):
94
+ return None
95
+ m = _FINAL_RE.search(line.strip())
96
+ if not m:
97
+ return None
98
+ return scrub_think_tags(m.group(1)).strip() or None
proxy.py CHANGED
@@ -19,6 +19,8 @@ import contextlib
19
  # Upstream pass-through
20
  import httpx
21
 
 
 
22
  from agent_server.helpers import normalize_content_to_text, _messages_to_task, _openai_response, _sse_headers
23
  from agent_server.openai_schemas import ChatMessage, ChatCompletionRequest
24
  from agent_server.sanitizing_think_tags import scrub_think_tags
@@ -57,102 +59,6 @@ app = fastapi.FastAPI()
57
  async def healthz():
58
  return {"ok": True}
59
 
60
-
61
- # ---------- Reasoning formatting for Chat-UI ----------
62
- def _format_reasoning_chunk(text: str, tag: str, idx: int) -> str:
63
- """
64
- Lightweight formatter for reasoning stream. Avoid huge code fences;
65
- make it readable and incremental. Also filters out ASCII/box-drawing noise.
66
- """
67
- text = scrub_think_tags(text).rstrip("\n")
68
- if not text:
69
- return ""
70
- noisy_prefixes = (
71
- "OpenAIServerModel",
72
- "Output message of the LLM",
73
- "─ Executing parsed code",
74
- "New run",
75
- "╭",
76
- "╰",
77
- "│",
78
- "━",
79
- "─",
80
- )
81
- stripped = text.strip()
82
- if not stripped:
83
- return ""
84
- # Lines made mostly of box drawing/separators
85
- if all(ch in " ─━╭╮╰╯│═·—-_=+•" for ch in stripped):
86
- return ""
87
- if any(stripped.startswith(p) for p in noisy_prefixes):
88
- return ""
89
- # Excessively long lines with little signal (no alphanumerics)
90
- if len(stripped) > 240 and not re.search(r"[A-Za-z0-9]{3,}", stripped):
91
- return ""
92
- # No tag/idx prefix; add a trailing blank line for readability in markdown
93
- return f"{stripped}\n\n"
94
-
95
-
96
- def _extract_final_text(item: typing.Any) -> typing.Optional[str]:
97
- if isinstance(item, dict) and ("__stdout__" in item or "__step__" in item):
98
- return None
99
- if isinstance(item, (bytes, bytearray)):
100
- try:
101
- item = item.decode("utf-8", errors="ignore")
102
- except Exception:
103
- item = str(item)
104
- if isinstance(item, str):
105
- s = scrub_think_tags(item.strip())
106
- return s or None
107
- # If it's a step-like object with an 'output' attribute, use that
108
- try:
109
- if not isinstance(item, (dict, list, bytes, bytearray)):
110
- out = getattr(item, "output", None)
111
- if out is not None:
112
- s = scrub_think_tags(str(out)).strip()
113
- if s:
114
- return s
115
- except Exception:
116
- pass
117
- if isinstance(item, dict):
118
- for key in ("content", "text", "message", "output", "final", "answer"):
119
- if key in item:
120
- val = item[key]
121
- if isinstance(val, (dict, list)):
122
- try:
123
- return scrub_think_tags(json.dumps(val, ensure_ascii=False))
124
- except Exception:
125
- return scrub_think_tags(str(val))
126
- if isinstance(val, (bytes, bytearray)):
127
- try:
128
- val = val.decode("utf-8", errors="ignore")
129
- except Exception:
130
- val = str(val)
131
- s = scrub_think_tags(str(val).strip())
132
- return s or None
133
- try:
134
- return scrub_think_tags(json.dumps(item, ensure_ascii=False))
135
- except Exception:
136
- return scrub_think_tags(str(item))
137
- try:
138
- return scrub_think_tags(str(item))
139
- except Exception:
140
- return None
141
-
142
-
143
- # Helper to parse explicit "Final answer:" from stdout lines
144
- _FINAL_RE = re.compile(r"(?:^|\\b)Final\\s+answer:\\s*(.+)$", flags=re.IGNORECASE)
145
-
146
-
147
- def _maybe_parse_final_from_stdout(line: str) -> typing.Optional[str]:
148
- if not isinstance(line, str):
149
- return None
150
- m = _FINAL_RE.search(line.strip())
151
- if not m:
152
- return None
153
- return scrub_think_tags(m.group(1)).strip() or None
154
-
155
-
156
  # ---------- Live stdout/stderr tee ----------
157
  class QueueWriter(io.TextIOBase):
158
  """
 
19
  # Upstream pass-through
20
  import httpx
21
 
22
+ from agent_server.formatting_reasoning import _format_reasoning_chunk, _extract_final_text, \
23
+ _maybe_parse_final_from_stdout
24
  from agent_server.helpers import normalize_content_to_text, _messages_to_task, _openai_response, _sse_headers
25
  from agent_server.openai_schemas import ChatMessage, ChatCompletionRequest
26
  from agent_server.sanitizing_think_tags import scrub_think_tags
 
59
  async def healthz():
60
  return {"ok": True}
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  # ---------- Live stdout/stderr tee ----------
63
  class QueueWriter(io.TextIOBase):
64
  """