projectdavid 1.32.5__py3-none-any.whl → 1.32.7__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.

@@ -11,12 +11,16 @@ LOG = UtilsInterface.LoggingUtility()
11
11
 
12
12
 
13
13
  class SynchronousInferenceStream:
14
+ """Wrap an async token/JSON stream in a synchronous iterator while
15
+ hiding function-call payloads from the UI.
16
+ """
17
+
14
18
  _GLOBAL_LOOP = asyncio.new_event_loop()
15
19
  asyncio.set_event_loop(_GLOBAL_LOOP)
16
20
 
17
- # --------------------------------------------------------------
18
- # ctor / setup
19
- # --------------------------------------------------------------
21
+ # ------------------------------------------------------------------ #
22
+ # construction / setup
23
+ # ------------------------------------------------------------------ #
20
24
  def __init__(self, inference) -> None:
21
25
  self.inference_client = inference
22
26
  self.user_id: Optional[str] = None
@@ -42,9 +46,9 @@ class SynchronousInferenceStream:
42
46
  self.run_id = run_id
43
47
  self.api_key = api_key
44
48
 
45
- # --------------------------------------------------------------
49
+ # ------------------------------------------------------------------ #
46
50
  # main streaming entry-point
47
- # --------------------------------------------------------------
51
+ # ------------------------------------------------------------------ #
48
52
  def stream_chunks(
49
53
  self,
50
54
  provider: str,
@@ -54,14 +58,23 @@ class SynchronousInferenceStream:
54
58
  timeout_per_chunk: float = 280.0,
55
59
  suppress_fc: bool = True,
56
60
  ) -> Generator[dict, None, None]:
61
+ """
62
+ Yield provider chunks synchronously.
63
+
64
+ When *suppress_fc* is True:
57
65
 
58
- resolved_api_key = api_key or self.api_key
66
+ `{"type":"function_call", …}` chunks are dropped.
67
+ • Inline `<fc> … </fc>` text is stripped.
68
+ • *Everything else* is forwarded unchanged.
69
+ """
59
70
 
60
- async def _stream_chunks_async():
71
+ resolved_key = api_key or self.api_key
72
+
73
+ async def _async_gen():
61
74
  async for chk in self.inference_client.stream_inference_response(
62
75
  provider=provider,
63
76
  model=model,
64
- api_key=resolved_api_key,
77
+ api_key=resolved_key,
65
78
  thread_id=self.thread_id,
66
79
  message_id=self.message_id,
67
80
  run_id=self.run_id,
@@ -69,35 +82,72 @@ class SynchronousInferenceStream:
69
82
  ):
70
83
  yield chk
71
84
 
72
- agen = _stream_chunks_async().__aiter__()
85
+ agen = _async_gen().__aiter__()
86
+
87
+ # ---------- inline suppressor chain ----------------------------
88
+ if suppress_fc:
89
+ _suppressor = FunctionCallSuppressor()
90
+ _peek_gate = PeekGate(_suppressor)
91
+
92
+ def _filter_text(txt: str) -> str:
93
+ return _peek_gate.feed(txt)
94
+
95
+ else:
96
+
97
+ def _filter_text(txt: str) -> str: # noqa: D401
98
+ return txt # pass-through
73
99
 
100
+ # ---------- main loop ------------------------------------------
74
101
  while True:
75
102
  try:
76
103
  chunk = self._GLOBAL_LOOP.run_until_complete(
77
104
  asyncio.wait_for(agen.__anext__(), timeout=timeout_per_chunk)
78
105
  )
79
106
 
80
- # Suppress only actual top-level function_call chunks
107
+ # provider-labelled function_call drop
81
108
  if suppress_fc and chunk.get("type") == "function_call":
82
- LOG.debug("[SUPPRESSOR] blocked top-level function_call chunk")
109
+ LOG.debug("[SUPPRESSOR] dropped provider function_call chunk")
83
110
  continue
84
111
 
85
- # Allow all other content implicitly
112
+ # never touch hot_code
113
+ if chunk.get("type") == "hot_code":
114
+ yield chunk
115
+ continue
116
+
117
+ # ③ never touch code_interpreter_stream previews
118
+ if (
119
+ chunk.get("stream_type") == "code_execution"
120
+ and chunk.get("chunk", {}).get("type") == "code_interpreter_stream"
121
+ ):
122
+ yield chunk
123
+ continue
124
+
125
+ # ④ scrub inline <fc> tags in plain-text content
126
+ if isinstance(chunk.get("content"), str):
127
+ chunk["content"] = _filter_text(chunk["content"])
128
+ if chunk["content"] == "":
129
+ # completely removed (or still buffering) – skip emit
130
+ continue
131
+
132
+ # ⑤ forward every other chunk verbatim
86
133
  yield chunk
87
134
 
88
135
  except StopAsyncIteration:
89
136
  LOG.info("Stream completed normally.")
90
137
  break
91
138
  except asyncio.TimeoutError:
92
- LOG.error("[TimeoutError] Timeout occurred, stopping stream.")
139
+ LOG.error(
140
+ "[TimeoutError] no chunk received for %.1f s – aborting",
141
+ timeout_per_chunk,
142
+ )
93
143
  break
94
- except Exception as e:
95
- LOG.error("Unexpected error during streaming completions: %s", e)
144
+ except Exception as exc: # pylint: disable=broad-except
145
+ LOG.error("Streaming error: %s", exc, exc_info=True)
96
146
  break
97
147
 
98
- # --------------------------------------------------------------
148
+ # ------------------------------------------------------------------ #
99
149
  # housekeeping
100
- # --------------------------------------------------------------
150
+ # ------------------------------------------------------------------ #
101
151
  @classmethod
102
152
  def shutdown_loop(cls) -> None:
103
153
  if cls._GLOBAL_LOOP and not cls._GLOBAL_LOOP.is_closed():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: projectdavid
3
- Version: 1.32.5
3
+ Version: 1.32.7
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=S0m-8lI9s4jk11n3CkK7msG-tIDknL56Mj3wIw5DKds,3682
18
+ projectdavid/clients/synchronous_inference_wrapper.py,sha256=-J21v2hDEP2yz343Gx0a05UW9sGUeAFq9eNT9iGP4Pc,5517
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
@@ -34,8 +34,8 @@ projectdavid/utils/monitor_launcher.py,sha256=3YAgJdeuaUvq3JGvpA4ymqFsAnk29nH5q9
34
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.5.dist-info/licenses/LICENSE,sha256=_8yjiEGttpS284BkfhXxfERqTRZW_tUaHiBB0GTJTMg,4563
38
- projectdavid-1.32.5.dist-info/METADATA,sha256=B783XTa8MFgSdxwkl5DMnkUbOOOs-smWtBl2OEsL_qg,10781
39
- projectdavid-1.32.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
- projectdavid-1.32.5.dist-info/top_level.txt,sha256=kil8GU4s7qYRfNnzGnFHhZnSNRSxgNG-J4HLgQMmMtw,13
41
- projectdavid-1.32.5.dist-info/RECORD,,
37
+ projectdavid-1.32.7.dist-info/licenses/LICENSE,sha256=_8yjiEGttpS284BkfhXxfERqTRZW_tUaHiBB0GTJTMg,4563
38
+ projectdavid-1.32.7.dist-info/METADATA,sha256=8SMqcudaTwLDg6B7m27v_U0mUAKjCFEHs9wtnt7W7Bg,10781
39
+ projectdavid-1.32.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
+ projectdavid-1.32.7.dist-info/top_level.txt,sha256=kil8GU4s7qYRfNnzGnFHhZnSNRSxgNG-J4HLgQMmMtw,13
41
+ projectdavid-1.32.7.dist-info/RECORD,,