Skip to content

Commit 16bb6b6

Browse files
committed
refactor: Rename session_id to storage_session_id across API and models
Updated the API responses and models to replace all instances of session_id with storage_session_id for consistency. This change includes updates to the upload, list, and batch file operations, as well as adjustments in the corresponding tests and documentation to reflect the new naming convention.
1 parent 019b3ec commit 16bb6b6

21 files changed

Lines changed: 140 additions & 100 deletions

src/api/files.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ async def upload_file(
172172
# Note: Production API returns different format with fileId instead of id
173173
return {
174174
"message": "success",
175+
"storage_session_id": session_id,
175176
"session_id": session_id,
176177
"files": [
177178
{"filename": file["name"], "fileId": file["id"]}
@@ -339,6 +340,7 @@ async def upload_files_batch(
339340

340341
return {
341342
"message": message,
343+
"storage_session_id": session_id,
342344
"session_id": session_id,
343345
"files": results,
344346
"succeeded": succeeded,
@@ -408,6 +410,7 @@ async def list_files(
408410
{
409411
"name": f"{session_id}/{file_info.file_id}",
410412
"id": file_info.file_id,
413+
"storage_session_id": session_id,
411414
"session_id": session_id,
412415
"content": None, # Not returned in list
413416
"size": file_info.size,

src/models/exec.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,37 @@
55
from typing import Dict, List, Optional, Any
66

77
# Third-party imports
8-
from pydantic import BaseModel, Field
8+
from pydantic import AliasChoices, BaseModel, ConfigDict, Field, computed_field
99

1010

1111
class FileRef(BaseModel):
1212
"""File reference model for execution response."""
1313

14+
model_config = ConfigDict(populate_by_name=True)
15+
1416
id: str
1517
name: str
16-
path: Optional[str] = None # Make path optional
17-
session_id: Optional[str] = None # Session ID for cross-message file persistence
18+
path: Optional[str] = None
19+
session_id: Optional[str] = None
1820
inherited: Optional[bool] = None
1921
entity_id: Optional[str] = None
2022
modified_from: Optional[Dict[str, str]] = None
2123

24+
@computed_field # type: ignore[prop-decorator]
25+
@property
26+
def storage_session_id(self) -> Optional[str]:
27+
return self.session_id
28+
2229

2330
class RequestFile(BaseModel):
2431
"""Request file model."""
2532

33+
model_config = ConfigDict(populate_by_name=True)
34+
2635
id: str
27-
session_id: str
36+
session_id: str = Field(
37+
validation_alias=AliasChoices("storage_session_id", "session_id"),
38+
)
2839
name: str
2940
entity_id: Optional[str] = None
3041

src/models/programmatic.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from typing import Any, Dict, List, Optional
1010

11-
from pydantic import BaseModel, Field, validator
11+
from pydantic import AliasChoices, BaseModel, ConfigDict, Field, validator
1212

1313
SUPPORTED_PTC_LANGUAGES = {"py", "bash"}
1414

@@ -51,12 +51,18 @@ class PTCFileInput(BaseModel):
5151
"""File payload for PTC initial execution.
5252
5353
Matches the LibreChat/librechat-agents CodeEnvFile shape:
54-
{session_id, id, name}
54+
{storage_session_id, id, name}
5555
"""
5656

57+
model_config = ConfigDict(populate_by_name=True)
58+
5759
id: str = Field(..., description="File identifier")
5860
name: str = Field(..., description="Original filename for the referenced file")
59-
session_id: str = Field(..., description="Source session for a referenced file")
61+
session_id: str = Field(
62+
...,
63+
description="Source session for a referenced file",
64+
validation_alias=AliasChoices("storage_session_id", "session_id"),
65+
)
6066

6167

6268
class ProgrammaticExecRequest(BaseModel):

src/services/orchestrator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,8 @@ async def _handle_generated_files(self, ctx: ExecutionContext) -> List[FileRef]:
786786
if meta.get("modified_from_id"):
787787
file_ref.modified_from = {
788788
"id": meta["modified_from_id"],
789-
"session_id": meta.get("modified_from_session_id") or "",
789+
"storage_session_id": meta.get("modified_from_session_id")
790+
or "",
790791
}
791792
generated.append(file_ref)
792793
logger.debug(

tests/functional/test_client_replay.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def _normalize_artifact_files(result: dict) -> list[dict]:
1212
session_id = result["session_id"]
1313
return [
1414
{
15-
"session_id": file_info.get("session_id") or session_id,
15+
"storage_session_id": file_info.get("storage_session_id") or session_id,
1616
"id": file_info["id"],
1717
"name": file_info["name"],
1818
}
@@ -36,7 +36,7 @@ async def _fetch_runtime_file_refs(
3636
file_id = name_parts[1].split(".")[0] if len(name_parts) > 1 else ""
3737
file_references.append(
3838
{
39-
"session_id": session_id,
39+
"storage_session_id": session_id,
4040
"id": file_id,
4141
"name": file_info["metadata"]["original-filename"],
4242
}
@@ -128,7 +128,7 @@ async def test_uploaded_files_follow_runtime_session_when_first_exec_has_no_outp
128128
data={"entity_id": unique_entity_id},
129129
)
130130
assert upload.status_code == 200, upload.text
131-
upload_session_id = upload.json()["session_id"]
131+
upload_session_id = upload.json()["storage_session_id"]
132132
upload_refs = await _fetch_runtime_file_refs(
133133
async_client, auth_headers, upload_session_id
134134
)
@@ -164,7 +164,7 @@ async def test_uploaded_files_survive_runtime_fallback_after_outputs_are_generat
164164
data={"entity_id": unique_entity_id},
165165
)
166166
assert upload.status_code == 200, upload.text
167-
upload_session_id = upload.json()["session_id"]
167+
upload_session_id = upload.json()["storage_session_id"]
168168
upload_refs = await _fetch_runtime_file_refs(
169169
async_client, auth_headers, upload_session_id
170170
)
@@ -298,7 +298,7 @@ async def test_ptc_fallback_refs_preserve_files_after_continuation(
298298
)
299299
assert upload.status_code == 200, upload.text
300300
upload_result = upload.json()
301-
session_id = upload_result["session_id"]
301+
session_id = upload_result["storage_session_id"]
302302

303303
initial = await _start_ptc_like_runtime(
304304
async_client,

tests/functional/test_concurrent_file_exec.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ async def test_large_file_exec_does_not_block_concurrent_requests(
5656
assert upload_resp.status_code == 200, f"Upload failed: {upload_resp.text}"
5757

5858
result = upload_resp.json()
59-
session_id = result["session_id"]
59+
session_id = result["storage_session_id"]
6060
file_id = result["files"][0]["fileId"]
6161
filename = result["files"][0]["filename"]
6262

@@ -72,7 +72,7 @@ async def exec_with_file(idx: int) -> tuple:
7272
"lang": "py",
7373
"session_id": session_id,
7474
"files": [
75-
{"id": file_id, "session_id": session_id, "name": filename}
75+
{"id": file_id, "storage_session_id": session_id, "name": filename}
7676
],
7777
},
7878
timeout=60.0,

tests/functional/test_exec_workflow.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ async def test_file_ref_does_not_leak_session_across_users(
172172
)
173173
assert upload.status_code == 200
174174
upload_data = upload.json()
175-
upload_session = upload_data["session_id"]
175+
upload_session = upload_data["storage_session_id"]
176176
file_id = upload_data["files"][0]["fileId"]
177177
filename = upload_data["files"][0]["filename"]
178178

@@ -187,7 +187,7 @@ async def test_file_ref_does_not_leak_session_across_users(
187187
"files": [
188188
{
189189
"id": file_id,
190-
"session_id": upload_session,
190+
"storage_session_id": upload_session,
191191
"name": filename,
192192
}
193193
],
@@ -208,7 +208,7 @@ async def test_file_ref_does_not_leak_session_across_users(
208208
"files": [
209209
{
210210
"id": file_id,
211-
"session_id": upload_session,
211+
"storage_session_id": upload_session,
212212
"name": filename,
213213
}
214214
],

tests/functional/test_files.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ async def test_upload_single_file(
2525
result = response.json()
2626

2727
assert result["message"] == "success"
28-
assert "session_id" in result
28+
assert "storage_session_id" in result
2929
assert len(result["files"]) == 1
3030
assert "fileId" in result["files"][0]
3131
assert "filename" in result["files"][0]
@@ -50,10 +50,10 @@ async def test_librechat_upload_format(
5050
assert response.json()["message"] == "success"
5151

5252
@pytest.mark.asyncio
53-
async def test_upload_returns_session_id(
53+
async def test_upload_returns_storage_session_id(
5454
self, async_client, auth_headers, unique_entity_id
5555
):
56-
"""Upload response includes session_id."""
56+
"""Upload response includes storage_session_id."""
5757
files = {"files": ("test.txt", b"content", "text/plain")}
5858
data = {"entity_id": unique_entity_id}
5959

@@ -65,8 +65,8 @@ async def test_upload_returns_session_id(
6565
)
6666

6767
result = response.json()
68-
assert "session_id" in result
69-
assert len(result["session_id"]) > 0
68+
assert "storage_session_id" in result
69+
assert len(result["storage_session_id"]) > 0
7070

7171
@pytest.mark.asyncio
7272
async def test_upload_returns_file_info(
@@ -120,7 +120,7 @@ async def test_list_files_after_upload(
120120
files=files,
121121
data={"entity_id": unique_entity_id},
122122
)
123-
session_id = upload.json()["session_id"]
123+
session_id = upload.json()["storage_session_id"]
124124

125125
# List files
126126
response = await async_client.get(
@@ -145,7 +145,7 @@ async def test_list_files_detail_simple(
145145
files=files,
146146
data={"entity_id": unique_entity_id},
147147
)
148-
session_id = upload.json()["session_id"]
148+
session_id = upload.json()["storage_session_id"]
149149

150150
# List with simple detail
151151
response = await async_client.get(
@@ -170,7 +170,7 @@ async def test_list_files_detail_summary(
170170
files=files,
171171
data={"entity_id": unique_entity_id},
172172
)
173-
session_id = upload.json()["session_id"]
173+
session_id = upload.json()["storage_session_id"]
174174

175175
# List with summary detail
176176
response = await async_client.get(
@@ -204,7 +204,7 @@ async def test_detail_full_has_original_filename_metadata(
204204
data={"entity_id": unique_entity_id},
205205
)
206206
assert upload.status_code == 200
207-
session_id = upload.json()["session_id"]
207+
session_id = upload.json()["storage_session_id"]
208208

209209
# Get full detail
210210
response = await async_client.get(
@@ -237,7 +237,7 @@ async def test_detail_full_has_required_fields(
237237
files=files,
238238
data={"entity_id": unique_entity_id},
239239
)
240-
session_id = upload.json()["session_id"]
240+
session_id = upload.json()["storage_session_id"]
241241

242242
response = await async_client.get(
243243
f"/files/{session_id}?detail=full",
@@ -278,7 +278,7 @@ async def test_download_uploaded_file(
278278
data={"entity_id": unique_entity_id},
279279
)
280280

281-
session_id = upload.json()["session_id"]
281+
session_id = upload.json()["storage_session_id"]
282282
file_id = upload.json()["files"][0]["fileId"]
283283

284284
response = await async_client.get(
@@ -322,7 +322,7 @@ async def test_uploaded_file_readable_at_mnt_data(
322322
)
323323
assert upload.status_code == 200
324324
upload_data = upload.json()
325-
session_id = upload_data["session_id"]
325+
session_id = upload_data["storage_session_id"]
326326
file_id = upload_data["files"][0]["fileId"]
327327
filename = upload_data["files"][0]["filename"]
328328

@@ -341,7 +341,7 @@ async def test_uploaded_file_readable_at_mnt_data(
341341
),
342342
"lang": "py",
343343
"session_id": session_id,
344-
"files": [{"id": file_id, "session_id": session_id, "name": filename}],
344+
"files": [{"id": file_id, "storage_session_id": session_id, "name": filename}],
345345
},
346346
)
347347

@@ -366,7 +366,7 @@ async def test_uploaded_file_readable_via_relative_path(
366366
data={"entity_id": unique_entity_id},
367367
)
368368
upload_data = upload.json()
369-
session_id = upload_data["session_id"]
369+
session_id = upload_data["storage_session_id"]
370370
file_id = upload_data["files"][0]["fileId"]
371371
filename = upload_data["files"][0]["filename"]
372372

@@ -377,7 +377,7 @@ async def test_uploaded_file_readable_via_relative_path(
377377
"code": f"print(open('{filename}').read())",
378378
"lang": "py",
379379
"session_id": session_id,
380-
"files": [{"id": file_id, "session_id": session_id, "name": filename}],
380+
"files": [{"id": file_id, "storage_session_id": session_id, "name": filename}],
381381
},
382382
)
383383

@@ -400,7 +400,7 @@ async def test_upload_execute_generate_download(
400400
data={"entity_id": unique_entity_id},
401401
)
402402
upload_data = upload.json()
403-
session_id = upload_data["session_id"]
403+
session_id = upload_data["storage_session_id"]
404404
file_id = upload_data["files"][0]["fileId"]
405405
filename = upload_data["files"][0]["filename"]
406406

@@ -424,7 +424,7 @@ async def test_upload_execute_generate_download(
424424
),
425425
"lang": "py",
426426
"session_id": session_id,
427-
"files": [{"id": file_id, "session_id": session_id, "name": filename}],
427+
"files": [{"id": file_id, "storage_session_id": session_id, "name": filename}],
428428
},
429429
)
430430

tests/functional/test_generated_artifacts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ async def test_generated_file_is_reused_on_follow_up_execution(
114114
"files": [
115115
{
116116
"id": generated_file["id"],
117-
"session_id": generate_result["session_id"],
117+
"storage_session_id": generate_result["session_id"],
118118
"name": generated_file["name"],
119119
}
120120
],

0 commit comments

Comments
 (0)