Skip to content

Commit 411e1d1

Browse files
committed
pass in context when saving cache so it's user is preserved
1 parent fe73419 commit 411e1d1

File tree

8 files changed

+60
-32
lines changed

8 files changed

+60
-32
lines changed

llms/extensions/app/db.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,11 @@ def prepare_thread(self, thread, id=None, user=None):
349349
thread["updatedAt"] = now
350350
initial_timestamp = int(time.time() * 1000) + 1
351351
if "messages" in thread:
352+
context = {}
353+
if user:
354+
context["user"] = user
352355
for idx, m in enumerate(thread["messages"]):
353-
self.ctx.cache_message_inline_data(m)
356+
self.ctx.cache_message_inline_data(m, context=context)
354357
if "timestamp" not in m:
355358
m["timestamp"] = initial_timestamp + idx
356359
# remove reasoning_details from all messages (can get huge)

llms/extensions/providers/chutes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ async def chat(self, chat, provider=None, context=None):
119119
"steps": steps,
120120
},
121121
),
122+
context=context,
122123
)
123124
return {
124125
"choices": [

llms/extensions/providers/google.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ async def chat(self, chat, context=None):
521521
base64_data,
522522
filename,
523523
ctx.to_file_info(chat, {"cost": cost}),
524+
context=context,
524525
)
525526
images.append(
526527
{

llms/extensions/providers/nvidia.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def to_response(self, response, chat, started_at, context=None):
3333
base64,
3434
filename,
3535
ctx.to_file_info(chat, {"seed": seed}),
36+
context=context,
3637
)
3738
return {
3839
"choices": [

llms/extensions/providers/openai.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ async def to_response(self, response, chat, started_at, context=None):
8989
image_data,
9090
f"{chat['model']}-{i}.{ext}",
9191
ctx.to_file_info(chat),
92+
context=context,
9293
)
9394
images.append(
9495
{

llms/extensions/providers/openrouter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def to_response(self, response, chat, started_at, context=None):
3333
model = chat["model"].split("/")[-1]
3434
filename = f"{model}-{choice['index']}.{ext}"
3535
relative_url, info = ctx.save_image_to_cache(
36-
base64_data, filename, ctx.to_file_info(chat, {"cost": cost})
36+
base64_data, filename, ctx.to_file_info(chat, {"cost": cost}), context=context
3737
)
3838
image["image_url"]["url"] = relative_url
3939

llms/extensions/providers/zai.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ async def chat(self, chat, provider=None, context=None):
155155
}
156156
info.update(usage)
157157
cache_url, info = ctx.save_image_to_cache(
158-
image_bytes, filename, image_info=info, ignore_info=True
158+
image_bytes, filename, image_info=info, ignore_info=True, context=context
159159
)
160160

161161
images.append(

llms/main.py

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ def file_ext_from_mimetype(mimetype, default="pdf"):
693693
return default
694694

695695

696-
def cache_message_inline_data(m):
696+
def cache_message_inline_data(m, context=None):
697697
"""
698698
Replaces and caches any inline data URIs in the message content.
699699
"""
@@ -714,7 +714,7 @@ def cache_message_inline_data(m):
714714
ext = image_ext_from_mimetype(header.split(":")[1])
715715
filename = f"image.{ext}" # Hash will handle uniqueness
716716

717-
cache_url, _ = save_image_to_cache(base64_data, filename, {}, ignore_info=True)
717+
cache_url, _ = save_image_to_cache(base64_data, filename, {}, ignore_info=True, context=context)
718718
image_url["url"] = cache_url
719719
except Exception as e:
720720
_log(f"Error caching inline image: {e}")
@@ -733,7 +733,7 @@ def cache_message_inline_data(m):
733733
filename = f"audio.{fmt}"
734734

735735
try:
736-
cache_url, _ = save_bytes_to_cache(base64_data, filename, {}, ignore_info=True)
736+
cache_url, _ = save_audio_to_cache(base64_data, filename, {}, ignore_info=True, context=context)
737737
input_audio["data"] = cache_url
738738
except Exception as e:
739739
_log(f"Error caching inline audio: {e}")
@@ -751,7 +751,7 @@ def cache_message_inline_data(m):
751751
ext = file_ext_from_mimetype(mimetype)
752752
filename = f"{filename}.{ext}"
753753

754-
cache_url, info = save_bytes_to_cache(base64_data, filename)
754+
cache_url, info = save_bytes_to_cache(base64_data, filename, context=context)
755755
file_info["file_data"] = cache_url
756756
file_info["filename"] = info["name"]
757757
except Exception as e:
@@ -767,7 +767,7 @@ def __init__(self, status, reason, body, headers=None):
767767
super().__init__(f"HTTP {status} {reason}")
768768

769769

770-
def save_bytes_to_cache(base64_data, filename, file_info=None, ignore_info=False):
770+
def save_bytes_to_cache(base64_data, filename, file_info=None, ignore_info=False, context=None):
771771
ext = filename.split(".")[-1]
772772
mimetype = get_file_mime_type(filename)
773773
content = base64.b64decode(base64_data) if isinstance(base64_data, str) else base64_data
@@ -790,6 +790,7 @@ def save_bytes_to_cache(base64_data, filename, file_info=None, ignore_info=False
790790
return url, json_from_file(info_path)
791791

792792
os.makedirs(os.path.dirname(full_path), exist_ok=True)
793+
user = context.get("user") if context else None
793794

794795
with open(full_path, "wb") as f:
795796
f.write(content)
@@ -802,6 +803,8 @@ def save_bytes_to_cache(base64_data, filename, file_info=None, ignore_info=False
802803
}
803804
if file_info:
804805
info.update(file_info)
806+
if user:
807+
info["user"] = user
805808

806809
# Save metadata
807810
info_path = os.path.splitext(full_path)[0] + ".info.json"
@@ -810,20 +813,21 @@ def save_bytes_to_cache(base64_data, filename, file_info=None, ignore_info=False
810813

811814
_dbg(f"Saved cached bytes and info: {relative_path}")
812815

813-
g_app.on_cache_saved_filters({"url": url, "info": info})
816+
user = context.get("user") if context else None
817+
g_app.on_cache_saved_filters({"url": url, "info": info, "user": user})
814818

815819
return url, info
816820

817821

818-
def save_audio_to_cache(base64_data, filename, audio_info, ignore_info=False):
819-
return save_bytes_to_cache(base64_data, filename, audio_info, ignore_info)
822+
def save_audio_to_cache(base64_data, filename, audio_info, ignore_info=False, context=None):
823+
return save_bytes_to_cache(base64_data, filename, audio_info, ignore_info, context)
820824

821825

822-
def save_video_to_cache(base64_data, filename, file_info, ignore_info=False):
823-
return save_bytes_to_cache(base64_data, filename, file_info, ignore_info)
826+
def save_video_to_cache(base64_data, filename, file_info, ignore_info=False, context=None):
827+
return save_bytes_to_cache(base64_data, filename, file_info, ignore_info, context)
824828

825829

826-
def save_image_to_cache(base64_data, filename, image_info, ignore_info=False):
830+
def save_image_to_cache(base64_data, filename, image_info, ignore_info=False, context=None):
827831
ext = filename.split(".")[-1]
828832
mimetype = get_file_mime_type(filename)
829833
content = base64.b64decode(base64_data) if isinstance(base64_data, str) else base64_data
@@ -846,6 +850,7 @@ def save_image_to_cache(base64_data, filename, image_info, ignore_info=False):
846850
return url, json_from_file(info_path)
847851

848852
os.makedirs(os.path.dirname(full_path), exist_ok=True)
853+
user = context.get("user") if context else None
849854

850855
with open(full_path, "wb") as f:
851856
f.write(content)
@@ -857,6 +862,8 @@ def save_image_to_cache(base64_data, filename, image_info, ignore_info=False):
857862
"name": filename,
858863
}
859864
info.update(image_info)
865+
if user:
866+
info["user"] = user
860867

861868
# If image, get dimensions
862869
if HAS_PIL and mimetype.startswith("image/"):
@@ -879,7 +886,7 @@ def save_image_to_cache(base64_data, filename, image_info, ignore_info=False):
879886

880887
_dbg(f"Saved image and info: {relative_path}")
881888

882-
g_app.on_cache_saved_filters({"url": url, "info": info})
889+
g_app.on_cache_saved_filters({"url": url, "info": info, "user": user})
883890

884891
return url, info
885892

@@ -1550,7 +1557,9 @@ def g_chat_request(template=None, text=None, model=None, system_prompt=None):
15501557
return chat
15511558

15521559

1553-
def tool_result_part(result: dict, function_name: Optional[str] = None, function_args: Optional[dict] = None):
1560+
def tool_result_part(
1561+
result: dict, function_name: Optional[str] = None, function_args: Optional[dict] = None, context=None
1562+
):
15541563
args = function_args or {}
15551564
type = result.get("type")
15561565
prompt = args.get("prompt") or args.get("text") or args.get("message")
@@ -1571,7 +1580,7 @@ def tool_result_part(result: dict, function_name: Optional[str] = None, function
15711580
if not base64_data:
15721581
_dbg(f"Image data not found for {function_name}")
15731582
return None, None
1574-
url, _ = save_image_to_cache(base64_data, filename, image_info=image_info, ignore_info=True)
1583+
url, _ = save_image_to_cache(base64_data, filename, image_info=image_info, ignore_info=True, context=context)
15751584
resource = {
15761585
"type": "image_url",
15771586
"image_url": {
@@ -1593,7 +1602,7 @@ def tool_result_part(result: dict, function_name: Optional[str] = None, function
15931602
if not base64_data:
15941603
_dbg(f"Audio data not found for {function_name}")
15951604
return None, None
1596-
url, _ = save_audio_to_cache(base64_data, filename, audio_info=audio_info, ignore_info=True)
1605+
url, _ = save_audio_to_cache(base64_data, filename, audio_info=audio_info, ignore_info=True, context=context)
15971606
resource = {
15981607
"type": "audio_url",
15991608
"audio_url": {
@@ -1618,7 +1627,7 @@ def tool_result_part(result: dict, function_name: Optional[str] = None, function
16181627
if not base64_data:
16191628
_dbg(f"File data not found for {function_name}")
16201629
return None, None
1621-
url, info = save_bytes_to_cache(base64_data, filename, file_info=file_info)
1630+
url, info = save_bytes_to_cache(base64_data, filename, file_info=file_info, context=context)
16221631
resource = {
16231632
"type": "file",
16241633
"file": {
@@ -1640,20 +1649,20 @@ def tool_result_part(result: dict, function_name: Optional[str] = None, function
16401649
return None, None
16411650

16421651

1643-
def g_tool_result(result, function_name: Optional[str] = None, function_args: Optional[dict] = None):
1652+
def g_tool_result(result, function_name: Optional[str] = None, function_args: Optional[dict] = None, context=None):
16441653
content = []
16451654
resources = []
16461655
args = function_args or {}
16471656
_dbg(f"{function_name} tool result type: {type(result)}")
16481657
if isinstance(result, dict):
1649-
text, res = tool_result_part(result, function_name, args)
1658+
text, res = tool_result_part(result, function_name, args, context)
16501659
if text:
16511660
content.append(text)
16521661
if res:
16531662
resources.append(res)
16541663
elif isinstance(result, list):
16551664
for item in result:
1656-
text, res = tool_result_part(item, function_name, args)
1665+
text, res = tool_result_part(item, function_name, args, context)
16571666
if text:
16581667
content.append(text)
16591668
if res:
@@ -1781,7 +1790,7 @@ def get_tool_property(function_name, prop_name):
17811790
return None
17821791

17831792

1784-
async def g_exec_tool(function_name, function_args):
1793+
async def g_exec_tool(function_name, function_args, context=None):
17851794
_log(f"g_exec_tool: {function_name}")
17861795
if function_name in g_app.tools:
17871796
try:
@@ -1792,9 +1801,9 @@ async def g_exec_tool(function_name, function_args):
17921801
is_async = inspect.iscoroutinefunction(func)
17931802
_dbg(f"Executing {'async' if is_async else 'sync'} tool '{function_name}' with args: {function_args}")
17941803
if is_async:
1795-
return g_tool_result(await func(**function_args), function_name, function_args)
1804+
return g_tool_result(await func(**function_args), function_name, function_args, context)
17961805
else:
1797-
return g_tool_result(func(**function_args), function_name, function_args)
1806+
return g_tool_result(func(**function_args), function_name, function_args, context)
17981807
except Exception as e:
17991808
return f"Error executing tool '{function_name}':\n{to_error_message(e)}", None
18001809
return f"Error: Tool '{function_name}' not found", None
@@ -3222,14 +3231,23 @@ def to_file_info(
32223231
return to_file_info(chat, info=info, response=response)
32233232

32243233
def save_image_to_cache(
3225-
self, base64_data: Union[str, bytes], filename: str, image_info: Dict[str, Any], ignore_info: bool = False
3234+
self,
3235+
base64_data: Union[str, bytes],
3236+
filename: str,
3237+
image_info: Dict[str, Any],
3238+
ignore_info: bool = False,
3239+
context: Optional[Dict[str, Any]] = None,
32263240
) -> Tuple[str, Optional[Dict[str, Any]]]:
3227-
return save_image_to_cache(base64_data, filename, image_info, ignore_info=ignore_info)
3241+
return save_image_to_cache(base64_data, filename, image_info, ignore_info=ignore_info, context=context)
32283242

32293243
def save_bytes_to_cache(
3230-
self, bytes_data: Union[str, bytes], filename: str, file_info: Optional[Dict[str, Any]]
3244+
self,
3245+
bytes_data: Union[str, bytes],
3246+
filename: str,
3247+
file_info: Optional[Dict[str, Any]],
3248+
context: Optional[Dict[str, Any]] = None,
32313249
) -> Tuple[str, Optional[Dict[str, Any]]]:
3232-
return save_bytes_to_cache(bytes_data, filename, file_info)
3250+
return save_bytes_to_cache(bytes_data, filename, file_info, context=context)
32333251

32343252
def text_from_file(self, path: str) -> str:
32353253
return text_from_file(path)
@@ -3478,8 +3496,8 @@ def context_to_username(self, context: Optional[Dict[str, Any]]) -> Optional[str
34783496
def should_cancel_thread(self, context: Dict[str, Any]) -> bool:
34793497
return should_cancel_thread(context)
34803498

3481-
def cache_message_inline_data(self, message: Dict[str, Any]):
3482-
return cache_message_inline_data(message)
3499+
def cache_message_inline_data(self, message: Dict[str, Any], context: Optional[Dict[str, Any]] = None):
3500+
return cache_message_inline_data(message, context=context)
34833501

34843502
async def exec_tool(self, name: str, args: Dict[str, Any]) -> Tuple[Optional[str], List[Dict[str, Any]]]:
34853503
return await g_exec_tool(name, args)
@@ -4303,6 +4321,7 @@ async def upload_handler(request):
43034321
if not is_authenticated:
43044322
return web.json_response(g_app.error_auth_required, status=401)
43054323

4324+
user = g_app.get_username(request)
43064325
reader = await request.multipart()
43074326

43084327
# Read first file field
@@ -4357,6 +4376,8 @@ async def upload_handler(request):
43574376
"type": mimetype,
43584377
"name": filename,
43594378
}
4379+
if user:
4380+
response_data["user"] = user
43604381

43614382
# If image, get dimensions
43624383
if HAS_PIL and mimetype.startswith("image/"):
@@ -4372,7 +4393,7 @@ async def upload_handler(request):
43724393
with open(info_path, "w") as f:
43734394
json.dump(response_data, f)
43744395

4375-
g_app.on_cache_saved_filters({"url": url, "info": response_data})
4396+
g_app.on_cache_saved_filters({"url": url, "info": response_data, "user": user})
43764397

43774398
return web.json_response(response_data)
43784399

0 commit comments

Comments
 (0)