jvserve 2.0.8__tar.gz → 2.0.10__tar.gz

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 jvserve might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jvserve
3
- Version: 2.0.8
3
+ Version: 2.0.10
4
4
  Summary: FastAPI webserver for loading and interaction with JIVAS agents.
5
5
  Home-page: https://github.com/TrueSelph/jvserve
6
6
  Author: TrueSelph Inc.
@@ -4,5 +4,5 @@ jvserve package initialization.
4
4
  This package provides the webserver for loading and interacting with JIVAS agents.
5
5
  """
6
6
 
7
- __version__ = "2.0.8"
7
+ __version__ = "2.0.10"
8
8
  __supported__jivas__versions__ = ["2.0.0"]
@@ -6,13 +6,14 @@ import os
6
6
  import string
7
7
  import time
8
8
  import traceback
9
- from typing import Any, Dict, List, Optional
9
+ from asyncio import sleep
10
+ from typing import Any, AsyncGenerator, Dict, Iterator, List, Optional
10
11
  from urllib.parse import quote, unquote
11
12
 
12
13
  import aiohttp
13
14
  import requests
14
15
  from fastapi import File, Form, Request, UploadFile
15
- from fastapi.responses import JSONResponse
16
+ from fastapi.responses import JSONResponse, StreamingResponse
16
17
  from jac_cloud.core.architype import AnchorState, Permission, Root
17
18
  from jac_cloud.core.context import (
18
19
  JASECI_CONTEXT,
@@ -129,6 +130,7 @@ class AgentInterface:
129
130
  AgentInterface.spawn_walker(
130
131
  walker_name=walker,
131
132
  attributes={
133
+ "headers": request.headers,
132
134
  "agent_id": agent_id,
133
135
  "params": params,
134
136
  "reporting": False,
@@ -243,7 +245,6 @@ class AgentInterface:
243
245
  @staticmethod
244
246
  def interact(payload: InteractPayload) -> dict:
245
247
  """Interact with the agent."""
246
-
247
248
  response = None
248
249
  ctx = AgentInterface.load_context()
249
250
  session_id = payload.session_id if payload.session_id else ""
@@ -273,15 +274,103 @@ class AgentInterface:
273
274
  },
274
275
  module_name="jivas.agent.action.interact",
275
276
  ),
276
- ).response
277
+ )
278
+
279
+ if payload.streaming:
280
+ # since streaming occurs asynchronously, we'll need to close the context for writebacks here
281
+ # at this point of closure, there will be an open interaction_node without a response
282
+ # our job hereafter is to stream to completion and then update and close this interaction_node with the final result
283
+
284
+ ctx.close()
285
+ if (
286
+ response is not None
287
+ and hasattr(response, "generator")
288
+ and hasattr(response, "interaction_node")
289
+ ):
290
+
291
+ interaction_node = response.interaction_node
292
+
293
+ async def generate(
294
+ generator: Iterator,
295
+ ) -> AsyncGenerator[str, None]:
296
+ """
297
+ Asynchronously yield data chunks from a response generator in Server-Sent Events (SSE) format.
298
+
299
+ Accumulates the full text content and yields each chunk as a JSON-encoded SSE message.
300
+ After all chunks are processed, updates the interaction node with the complete generated text and triggers an update in the graph context.
301
+
302
+ Yields:
303
+ str: A JSON-encoded string representing the current chunk of data in SSE format.
304
+ """
305
+ full_text = ""
306
+ total_tokens = 0
307
+ try:
308
+ for chunk in generator:
309
+ full_text += chunk.content
310
+ total_tokens += 1 # each chunk is a token, let's tally
311
+ await sleep(0.025)
312
+ yield (
313
+ "data: "
314
+ + json.dumps(
315
+ {
316
+ "id": interaction_node.id,
317
+ "content": chunk.content,
318
+ "session_id": interaction_node.response.get(
319
+ "session_id"
320
+ ),
321
+ "type": chunk.type,
322
+ "metadata": chunk.response_metadata,
323
+ }
324
+ )
325
+ + "\n\n"
326
+ )
327
+ # Update the interaction node with the fully generated text
328
+ actx = await AgentInterface.load_context_async()
329
+ try:
330
+ interaction_node.set_text_message(message=full_text)
331
+ interaction_node.add_tokens(total_tokens)
332
+ _Jac.spawn_call(
333
+ NodeAnchor.ref(interaction_node.id).architype,
334
+ AgentInterface.spawn_walker(
335
+ walker_name="update_interaction",
336
+ attributes={
337
+ "interaction_data": interaction_node.export(),
338
+ },
339
+ module_name="jivas.agent.action.update_interaction",
340
+ ),
341
+ )
342
+ finally:
343
+ if actx:
344
+ actx.close()
345
+
346
+ except Exception as e:
347
+ AgentInterface.LOGGER.error(
348
+ f"Exception in streaming generator: {e}, {traceback.format_exc()}"
349
+ )
350
+
351
+ return StreamingResponse(
352
+ generate(response.generator),
353
+ media_type="text/event-stream",
354
+ )
355
+
356
+ else:
357
+ AgentInterface.LOGGER.error(
358
+ "Response is None or missing required attributes for streaming."
359
+ )
360
+ return {}
361
+
362
+ else:
363
+ response = response.response
364
+ ctx.close()
365
+ return response if response else {}
366
+
277
367
  except Exception as e:
278
368
  AgentInterface.EXPIRATION = None
279
369
  AgentInterface.LOGGER.error(
280
370
  f"an exception occurred: {e}, {traceback.format_exc()}"
281
371
  )
282
-
283
- ctx.close()
284
- return response if response else {}
372
+ ctx.close()
373
+ return {}
285
374
 
286
375
  @staticmethod
287
376
  def pulse(action_label: str, agent_id: str = "") -> dict:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jvserve
3
- Version: 2.0.8
3
+ Version: 2.0.10
4
4
  Summary: FastAPI webserver for loading and interaction with JIVAS agents.
5
5
  Home-page: https://github.com/TrueSelph/jvserve
6
6
  Author: TrueSelph Inc.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes