Feature/streaming llm phase 1 (#566)

* Tidy up duplicate tech specs in doc directory

* Streaming LLM text-completion service tech spec.

* text-completion and prompt interfaces

* streaming change applied to all LLMs, so far tested with VertexAI

* Skip Pinecone unit tests, upstream module issue is affecting things, tests are passing again

* Added agent streaming, not working and has broken tests
This commit is contained in:
cybermaggedon 2025-11-26 09:59:10 +00:00 committed by GitHub
parent 943a9d83b0
commit 310a2deb06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 2684 additions and 937 deletions

View file

@ -191,6 +191,9 @@ class Processor(AgentService):
try:
# Check if streaming is enabled
streaming = getattr(request, 'streaming', False)
if request.history:
history = [
Action(
@ -215,12 +218,27 @@ class Processor(AgentService):
logger.debug(f"Think: {x}")
r = AgentResponse(
answer=None,
error=None,
thought=x,
observation=None,
)
if streaming:
# Streaming format
r = AgentResponse(
chunk_type="thought",
content=x,
end_of_message=True,
end_of_dialog=False,
# Legacy fields for backward compatibility
answer=None,
error=None,
thought=x,
observation=None,
)
else:
# Legacy format
r = AgentResponse(
answer=None,
error=None,
thought=x,
observation=None,
)
await respond(r)
@ -228,12 +246,55 @@ class Processor(AgentService):
logger.debug(f"Observe: {x}")
r = AgentResponse(
answer=None,
error=None,
thought=None,
observation=x,
)
if streaming:
# Streaming format
r = AgentResponse(
chunk_type="observation",
content=x,
end_of_message=True,
end_of_dialog=False,
# Legacy fields for backward compatibility
answer=None,
error=None,
thought=None,
observation=x,
)
else:
# Legacy format
r = AgentResponse(
answer=None,
error=None,
thought=None,
observation=x,
)
await respond(r)
async def answer(x):
logger.debug(f"Answer: {x}")
if streaming:
# Streaming format
r = AgentResponse(
chunk_type="answer",
content=x,
end_of_message=False, # More chunks may follow
end_of_dialog=False,
# Legacy fields for backward compatibility
answer=None,
error=None,
thought=None,
observation=None,
)
else:
# Legacy format - shouldn't be called in non-streaming mode
r = AgentResponse(
answer=x,
error=None,
thought=None,
observation=None,
)
await respond(r)
@ -273,7 +334,9 @@ class Processor(AgentService):
history = history,
think = think,
observe = observe,
answer = answer,
context = UserAwareContext(flow, request.user),
streaming = streaming,
)
logger.debug(f"Action: {act}")
@ -287,11 +350,26 @@ class Processor(AgentService):
else:
f = json.dumps(act.final)
r = AgentResponse(
answer=act.final,
error=None,
thought=None,
)
if streaming:
# Streaming format - send end-of-dialog marker
# Answer chunks were already sent via think() callback during parsing
r = AgentResponse(
chunk_type="answer",
content="", # Empty content, just marking end of dialog
end_of_message=True,
end_of_dialog=True,
# Legacy fields for backward compatibility
answer=act.final,
error=None,
thought=None,
)
else:
# Legacy format - send complete answer
r = AgentResponse(
answer=act.final,
error=None,
thought=None,
)
await respond(r)
@ -321,7 +399,9 @@ class Processor(AgentService):
observation=h.observation
)
for h in history
]
],
user=request.user,
streaming=streaming,
)
await next(r)
@ -336,14 +416,32 @@ class Processor(AgentService):
logger.debug("Send error response...")
r = AgentResponse(
error=Error(
type = "agent-error",
message = str(e),
),
response=None,
error_obj = Error(
type = "agent-error",
message = str(e),
)
# Check if streaming was enabled (may not be set if error occurred early)
streaming = getattr(request, 'streaming', False) if 'request' in locals() else False
if streaming:
# Streaming format
r = AgentResponse(
chunk_type="error",
content=str(e),
end_of_message=True,
end_of_dialog=True,
# Legacy fields for backward compatibility
error=error_obj,
response=None,
)
else:
# Legacy format
r = AgentResponse(
error=error_obj,
response=None,
)
await respond(r)
@staticmethod