projectdavid 1.32.0__py3-none-any.whl → 1.32.2__py3-none-any.whl

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.

Potentially problematic release.


This version of projectdavid might be problematic. Click here for more details.

@@ -49,15 +49,14 @@ class SynchronousInferenceStream:
49
49
  self,
50
50
  provider: str,
51
51
  model: str,
52
- *, # keyword-only from here
52
+ *,
53
53
  api_key: Optional[str] = None,
54
54
  timeout_per_chunk: float = 280.0,
55
- suppress_fc: bool = True, # ← NEW switch
55
+ suppress_fc: bool = True,
56
56
  ) -> Generator[dict, None, None]:
57
57
 
58
58
  resolved_api_key = api_key or self.api_key
59
59
 
60
- # ------------- build async generator ----------------------
61
60
  async def _stream_chunks_async():
62
61
  async for chk in self.inference_client.stream_inference_response(
63
62
  provider=provider,
@@ -72,10 +71,10 @@ class SynchronousInferenceStream:
72
71
 
73
72
  agen = _stream_chunks_async().__aiter__()
74
73
 
75
- # ------------- optional suppression chain -----------------
74
+ # ---------- suppression chain ----------
76
75
  if suppress_fc:
77
76
  _suppressor = FunctionCallSuppressor()
78
- _peek_gate = PeekGate(_suppressor) # 2 KB default
77
+ _peek_gate = PeekGate(_suppressor)
79
78
 
80
79
  def _filter_text(txt: str) -> str:
81
80
  return _peek_gate.feed(txt)
@@ -85,7 +84,7 @@ class SynchronousInferenceStream:
85
84
  def _filter_text(txt: str) -> str: # no-op
86
85
  return txt
87
86
 
88
- # ----------------------------------------------------------
87
+ # ---------------------------------------
89
88
 
90
89
  while True:
91
90
  try:
@@ -93,18 +92,23 @@ class SynchronousInferenceStream:
93
92
  asyncio.wait_for(agen.__anext__(), timeout=timeout_per_chunk)
94
93
  )
95
94
 
96
- # --- provider-labelled function_call blocks -------
95
+ # provider-labelled function_call
97
96
  if suppress_fc and chunk.get("type") == "function_call":
98
- LOG.debug(
99
- "[SUPPRESSOR] blocked provider-labelled function_call chunk"
100
- )
97
+ LOG.debug("[SUPPRESSOR] blocked provider-labelled function_call")
101
98
  continue
102
99
 
103
- # --- inline content filtering --------------------
100
+ # inline content
104
101
  if isinstance(chunk.get("content"), str):
105
102
  chunk["content"] = _filter_text(chunk["content"])
106
- if not chunk["content"]:
107
- # fully suppressed skip forwarding
103
+ if chunk["content"] == "":
104
+ continue # fully suppressed (or still peeking)
105
+
106
+ # additional raw inline suppression for partial JSON
107
+ if (
108
+ '"name": "code_interpreter"' in chunk["content"]
109
+ and '"arguments": {"code"' in chunk["content"]
110
+ ):
111
+ LOG.debug("[SUPPRESSOR] inline code_interpreter match blocked")
108
112
  continue
109
113
 
110
114
  yield chunk
@@ -1,3 +1,6 @@
1
+ # ------------------------------------------------------------------
2
+ # utils.function_call_suppressor (unchanged except for logger)
3
+ # ------------------------------------------------------------------
1
4
  import re
2
5
 
3
6
  from projectdavid_common.utilities.logging_service import LoggingUtility
@@ -5,9 +8,6 @@ from projectdavid_common.utilities.logging_service import LoggingUtility
5
8
  LOG = LoggingUtility()
6
9
 
7
10
 
8
- # ─────────────────────────────────────────────────────────────────────
9
- # function-call filter helpers (unchanged except for logger)
10
- # ─────────────────────────────────────────────────────────────────────
11
11
  class FunctionCallSuppressor:
12
12
  OPEN_RE = re.compile(r"<\s*fc\s*>", re.I)
13
13
  CLOSE_RE = re.compile(r"</\s*fc\s*>", re.I)
@@ -16,10 +16,9 @@ class FunctionCallSuppressor:
16
16
  self.in_fc = False
17
17
  self.buf = ""
18
18
 
19
- def filter_chunk(self, chunk: str) -> str:
20
- self.buf += chunk
19
+ def filter_chunk(self, txt: str) -> str:
20
+ self.buf += txt
21
21
  out = ""
22
-
23
22
  while self.buf:
24
23
  if not self.in_fc:
25
24
  m = self.OPEN_RE.search(self.buf)
@@ -34,7 +33,7 @@ class FunctionCallSuppressor:
34
33
  else:
35
34
  m = self.CLOSE_RE.search(self.buf)
36
35
  if not m:
37
- break # wait for more tokens
36
+ break
38
37
  LOG.debug("[SUPPRESSOR] </fc> detected — block suppressed")
39
38
  self.buf = self.buf[m.end() :]
40
39
  self.in_fc = False
@@ -1,3 +1,6 @@
1
+ # ------------------------------------------------------------------
2
+ # utils.peek_gate (progressive flush version)
3
+ # ------------------------------------------------------------------
1
4
  import re
2
5
 
3
6
  from projectdavid_common.utilities.logging_service import LoggingUtility
@@ -9,17 +12,35 @@ LOG = LoggingUtility()
9
12
 
10
13
  class PeekGate:
11
14
  """
12
- Turns the suppressor on only if a <fc> block appears in the first
13
- `peek_limit` characters; otherwise passes text through unchanged.
15
+ Streams *most* text immediately while the gate decides whether
16
+ a <fc> block will appear.
17
+ • Keeps only SAFETY_MARGIN bytes back so a tag split across two
18
+ chunks can still be caught.
14
19
  """
15
20
 
21
+ SAFETY_MARGIN = 8 # enough to hold "<fc>" + whitespace
22
+
16
23
  def __init__(self, downstream: FunctionCallSuppressor, peek_limit: int = 2048):
17
24
  self.downstream = downstream
18
25
  self.peek_limit = peek_limit
19
26
  self.buf = ""
20
- self.mode = "peeking" # -> "normal" after decision
27
+ self.mode = "peeking" # "normal" after decision
21
28
  self.suppressing = False
22
29
 
30
+ # ----------------------------------------------------------
31
+ def _safe_flush(self, new_txt: str = "") -> str:
32
+ """
33
+ Return everything except the last SAFETY_MARGIN chars,
34
+ which are kept for tag-boundary safety.
35
+ """
36
+ self.buf += new_txt
37
+ if len(self.buf) <= self.SAFETY_MARGIN:
38
+ return ""
39
+ flush_len = len(self.buf) - self.SAFETY_MARGIN
40
+ head, self.buf = self.buf[:flush_len], self.buf[flush_len:]
41
+ return head
42
+
43
+ # ----------------------------------------------------------
23
44
  def feed(self, txt: str) -> str:
24
45
  # decision already taken
25
46
  if self.mode == "normal":
@@ -28,22 +49,23 @@ class PeekGate:
28
49
  # still peeking …
29
50
  self.buf += txt
30
51
  m = re.search(r"<\s*fc\s*>", self.buf, flags=re.I)
31
- if m: # found a tag
52
+ if m: # tag found
32
53
  head = self.buf[: m.start()]
33
- LOG.debug("[PEEK] <fc> located after leading text – engaging suppressor")
54
+ LOG.debug("[PEEK] <fc> located – engaging suppressor")
34
55
  self.suppressing = True
35
56
  self.mode = "normal"
36
- tail = self.buf[m.start() :]
37
- self.buf = ""
57
+ tail, self.buf = self.buf[m.start() :], ""
38
58
  return head + self.downstream.filter_chunk(tail)
39
59
 
40
- if len(self.buf) >= self.peek_limit: # give up
60
+ # no tag yet overflow?
61
+ if len(self.buf) >= self.peek_limit:
41
62
  LOG.debug(
42
- "[PEEK] no <fc> tag within first %d chars – no suppression",
63
+ "[PEEK] no <fc> tag within first %d chars – " "streaming normally",
43
64
  self.peek_limit,
44
65
  )
45
- self.mode = "normal"
46
- self.suppressing = False
47
- out, self.buf = self.buf, ""
48
- return out
49
- return ""
66
+ flush, self.mode = self.buf, "normal"
67
+ self.buf = ""
68
+ return flush
69
+
70
+ # still undecided → flush safe part
71
+ return self._safe_flush()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: projectdavid
3
- Version: 1.32.0
3
+ Version: 1.32.2
4
4
  Summary: Python SDK for interacting with the Entities Assistant API.
5
5
  Author-email: Francis Neequaye Armah <francis.neequaye@projectdavid.co.uk>
6
6
  License: PolyForm Noncommercial License 1.0.0
@@ -15,7 +15,7 @@ projectdavid/clients/files_client.py,sha256=XkIDzbQFGDrd88taf0Kouc_4YJOPIYEHiIyW
15
15
  projectdavid/clients/inference_client.py,sha256=xz4ACPv5Tkis604QxO5mJX1inH_TGDfQP-31geETYpE,6609
16
16
  projectdavid/clients/messages_client.py,sha256=467xeIt3VYs6cG8-bl-eDRi_auWOPmfd5tSJDmQSJUI,17232
17
17
  projectdavid/clients/runs.py,sha256=-fXOq5L9w2efDPmZkNxb0s2yjl6oN0XN4_aLXqaeceo,25270
18
- projectdavid/clients/synchronous_inference_wrapper.py,sha256=sikHDDmx3NFhK9eoFL0PVlZ0CaFG-CIWfDmgFkH48Do,4594
18
+ projectdavid/clients/synchronous_inference_wrapper.py,sha256=Rv7TGZBnzMOBDw3BwguDOHcVmwLvcjHp7j6V8OAqpwM,4686
19
19
  projectdavid/clients/threads_client.py,sha256=ekzU5w14zftmtmFkiec3NC90Of-_KVSUY1qH9cmfSFg,6771
20
20
  projectdavid/clients/tools_client.py,sha256=GkCVOmwpAoPqVt6aYmH0G1HIFha3iEwR9IIf9teR0j8,11487
21
21
  projectdavid/clients/users_client.py,sha256=eCuUb9qvyH1GUFhZu6TRL9zdoK-qzHSs8-Vmrk_0mmg,13729
@@ -29,13 +29,13 @@ projectdavid/synthesis/prompt.py,sha256=Jlya6avnWV5ryaJaibt4W29XYxRlJRV6rwHfjgYy
29
29
  projectdavid/synthesis/reranker.py,sha256=aFjdLDoqnhgzxPIoRfs4y_Z_F6T88g5Sg8R5m0HMxdU,868
30
30
  projectdavid/synthesis/retriever.py,sha256=8R5HIgPXMKIQxV5KsN8u_gVVP4JY-wsDwJd92A-74-o,2300
31
31
  projectdavid/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
- projectdavid/utils/function_call_suppressor.py,sha256=uTjB6e1JDs_nkSVtRuqretb-zYDbAAC3jN3gpzqVauo,1616
32
+ projectdavid/utils/function_call_suppressor.py,sha256=LsDhySVH0kS8nydPBrHrOtT30yhVvwU24QHApGu1P34,1305
33
33
  projectdavid/utils/monitor_launcher.py,sha256=3YAgJdeuaUvq3JGvpA4ymqFsAnk29nH5q93cwStP4hc,2836
34
- projectdavid/utils/peek_gate.py,sha256=odQIZJYTygRPu5IfOBBgqqeSXiWfQ73-lRBYM2KbY4I,1630
34
+ projectdavid/utils/peek_gate.py,sha256=5whMRnDOQjATRpThWDJkvY9ScXuJ7Sd_-9rvGgXeTAQ,2532
35
35
  projectdavid/utils/run_monitor.py,sha256=F_WkqIP-qnWH-4llIbileWWLfRj2Q1Cg-ni23SR1rec,3786
36
36
  projectdavid/utils/vector_search_formatter.py,sha256=YTe3HPGec26qGY7uxY8_GS8lc4QaN6aNXMzkl29nZpI,1735
37
- projectdavid-1.32.0.dist-info/licenses/LICENSE,sha256=_8yjiEGttpS284BkfhXxfERqTRZW_tUaHiBB0GTJTMg,4563
38
- projectdavid-1.32.0.dist-info/METADATA,sha256=F3ZVLx0ylA3omK6BEsxsTrbaroIwcE42FO0GUcT0EkU,10781
39
- projectdavid-1.32.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
- projectdavid-1.32.0.dist-info/top_level.txt,sha256=kil8GU4s7qYRfNnzGnFHhZnSNRSxgNG-J4HLgQMmMtw,13
41
- projectdavid-1.32.0.dist-info/RECORD,,
37
+ projectdavid-1.32.2.dist-info/licenses/LICENSE,sha256=_8yjiEGttpS284BkfhXxfERqTRZW_tUaHiBB0GTJTMg,4563
38
+ projectdavid-1.32.2.dist-info/METADATA,sha256=FS7ZUJmxyRntFkY4FQjaDPXkqihI8i6yzwpYFC_N2rI,10781
39
+ projectdavid-1.32.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
+ projectdavid-1.32.2.dist-info/top_level.txt,sha256=kil8GU4s7qYRfNnzGnFHhZnSNRSxgNG-J4HLgQMmMtw,13
41
+ projectdavid-1.32.2.dist-info/RECORD,,