Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions hindsight-api-slim/hindsight_api/api/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -2596,6 +2596,10 @@ class OperationResponse(BaseModel):
task_type: str
items_count: int
document_id: str | None = None
filename: str | None = Field(
default=None,
description="Original filename for file-conversion operations (file_convert_retain); null for other task types.",
)
created_at: str
updated_at: str | None = Field(
default=None,
Expand Down
4 changes: 3 additions & 1 deletion hindsight-api-slim/hindsight_api/engine/memory_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -11447,7 +11447,8 @@ async def list_operations(
"id": str(row["operation_id"]),
"task_type": row["operation_type"],
"items_count": result_metadata.get("items_count", 0),
"document_id": None,
"document_id": result_metadata.get("document_id"),
"filename": result_metadata.get("original_filename"),
"created_at": row["created_at"].isoformat(),
"updated_at": row["updated_at"].isoformat() if row["updated_at"] else None,
"status": row["status"],
Expand Down Expand Up @@ -12432,6 +12433,7 @@ async def submit_async_file_retain(
task_payload=task_payload,
result_metadata={
"original_filename": file.filename,
"document_id": item["document_id"],
},
dedupe_by_bank=False,
)
Expand Down
53 changes: 53 additions & 0 deletions hindsight-api-slim/tests/test_file_retain.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,59 @@ async def read(self):
assert len(doc["original_text"]) > 0


@pytest.mark.asyncio
async def test_list_operations_surfaces_file_document_id_and_filename(memory_no_llm_verify, sample_txt_content):
"""list_operations must expose document_id + filename for file_convert_retain ops.

The control plane derives its pending-upload rows from these fields (it
matches an in-flight operation to the real document via document_id and
labels the row with the original filename), so both must round-trip from
the operation's result_metadata into the list response.
"""
from hindsight_api.models import RequestContext

bank_id = "test_file_op_fields_bank"
context = RequestContext(internal=True)
await memory_no_llm_verify.get_bank_profile(bank_id, request_context=context)

class MockFile:
def __init__(self, content, filename, content_type):
self.content = content
self.filename = filename
self.content_type = content_type

async def read(self):
return self.content

file_items = [
{
"file": MockFile(sample_txt_content, "report.txt", "text/plain"),
"document_id": "doc_op_fields",
"context": None,
"metadata": {},
"tags": [],
"timestamp": None,
"parser": ["markitdown"],
}
]

await memory_no_llm_verify.submit_async_file_retain(
bank_id=bank_id,
file_items=file_items,
document_tags=None,
request_context=context,
)

result = await memory_no_llm_verify.list_operations(
bank_id, task_type="file_convert_retain", request_context=context
)

file_ops = [op for op in result["operations"] if op["task_type"] == "file_convert_retain"]
assert len(file_ops) == 1
assert file_ops[0]["document_id"] == "doc_op_fields"
assert file_ops[0]["filename"] == "report.txt"


@pytest.mark.asyncio
async def test_async_file_retain_serializes_datetime_timestamp(memory_no_llm_verify, sample_txt_content):
"""Async file retain should accept Python datetimes in task payloads."""
Expand Down
3 changes: 3 additions & 0 deletions hindsight-clients/go/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6982,6 +6982,9 @@ components:
document_id:
nullable: true
type: string
filename:
nullable: true
type: string
created_at:
title: Created At
type: string
Expand Down
46 changes: 46 additions & 0 deletions hindsight-clients/go/model_operation_response.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ class OperationResponse(BaseModel):
task_type: StrictStr
items_count: StrictInt
document_id: Optional[StrictStr] = None
filename: Optional[StrictStr] = None
created_at: StrictStr
updated_at: Optional[StrictStr] = None
status: StrictStr
error_message: Optional[StrictStr]
retry_count: Optional[StrictInt] = None
next_retry_at: Optional[StrictStr] = None
progress: Optional[OperationProgress] = None
__properties: ClassVar[List[str]] = ["id", "task_type", "items_count", "document_id", "created_at", "updated_at", "status", "error_message", "retry_count", "next_retry_at", "progress"]
__properties: ClassVar[List[str]] = ["id", "task_type", "items_count", "document_id", "filename", "created_at", "updated_at", "status", "error_message", "retry_count", "next_retry_at", "progress"]

model_config = ConfigDict(
populate_by_name=True,
Expand Down Expand Up @@ -87,6 +88,11 @@ def to_dict(self) -> Dict[str, Any]:
if self.document_id is None and "document_id" in self.model_fields_set:
_dict['document_id'] = None

# set to None if filename (nullable) is None
# and model_fields_set contains the field
if self.filename is None and "filename" in self.model_fields_set:
_dict['filename'] = None

# set to None if updated_at (nullable) is None
# and model_fields_set contains the field
if self.updated_at is None and "updated_at" in self.model_fields_set:
Expand Down Expand Up @@ -128,6 +134,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
"task_type": obj.get("task_type"),
"items_count": obj.get("items_count"),
"document_id": obj.get("document_id"),
"filename": obj.get("filename"),
"created_at": obj.get("created_at"),
"updated_at": obj.get("updated_at"),
"status": obj.get("status"),
Expand Down
6 changes: 6 additions & 0 deletions hindsight-clients/typescript/generated/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2755,6 +2755,12 @@ export type OperationResponse = {
* Document Id
*/
document_id?: string | null;
/**
* Filename
*
* Original filename for file-conversion operations (file_convert_retain); null for other task types.
*/
filename?: string | null;
/**
* Created At
*/
Expand Down
6 changes: 6 additions & 0 deletions hindsight-control-plane/src/components/bank-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,12 @@ function BankSelectorInner() {
setDocAsync(false);
setUploadProgress("");

// Nudge the documents view to surface the new file_convert_retain
// operations right away (it derives pending rows from the server).
if (typeof window !== "undefined") {
window.dispatchEvent(new Event("hindsight:documents-refresh"));
}

// Navigate to documents view
router.push(bankRoute(currentBank!, "?view=documents"));
} catch {
Expand Down
Loading
Loading