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
2 changes: 1 addition & 1 deletion application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.260.009"
VERSION = "0.260.010"
IS_DEVELOPMENT = is_development_env_enabled()

SESSION_COOKIE_SAMESITE = os.getenv('SESSION_COOKIE_SAMESITE', 'Lax')
Expand Down
58 changes: 51 additions & 7 deletions application/single_app/functions_generated_file_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,10 +492,12 @@
)
if output_format in {GENERATED_FILE_FORMAT_DOCX, GENERATED_FILE_FORMAT_PDF}:
return (
f'The user requested a downloadable {output_format.upper()} artifact. Provide a clear final '
'response grounded in the available evidence. Structured function results from this turn may '
'be included as labeled tables in the generated file; do not invent rows or claim an attachment '
'exists before the file-output finalizer publishes it.'
f'The user requested a downloadable {output_format.upper()} artifact. The server renders and '
'attaches the file after generation. Provide a clear final response grounded in the available '
'evidence. Structured function results from this turn may be included as labeled tables in the '
'generated file. Do not claim that you cannot create or attach files, do not tell the user to '
'copy or save the content manually, do not invent rows, and do not claim an attachment exists '
'before the file-output finalizer publishes it.'
)
return ''

Expand Down Expand Up @@ -533,6 +535,8 @@

assistant_text = str(assistant_content or '').strip()
assistant_rows = extract_assistant_table_entries(assistant_text)
if not assistant_rows and _assistant_reply_requests_clarification(assistant_text):
return None
function_rows = extract_authorized_function_result_rows(function_results)
row_provenance = ROW_SOURCE_CURRENT_ACTION
if not assistant_rows and not function_rows and prior_function_results_loader is not None:
Expand All @@ -547,8 +551,6 @@
) if function_rows else {'allowed': False, 'reason_code': 'source_result_incomplete'}

if output_format == GENERATED_FILE_FORMAT_CSV:
if not assistant_rows and _assistant_reply_requests_clarification(assistant_text):
return None
use_function_rows = bool(function_rows) and bool(function_passthrough.get('allowed')) and (
not assistant_rows
or _assistant_rows_sample_function_rows(assistant_rows, function_rows)
Expand Down Expand Up @@ -584,8 +586,50 @@
row_source=row_source,
assistant_content=assistant_text,
title=title,
passthrough_reason_code=(function_passthrough.get('reason_code') if row_source == 'structured function result' else None),
passthrough_reason_code=(

Check warning on line 589 in application/single_app/functions_generated_file_exports.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
function_passthrough.get('reason_code') if row_source in FUNCTION_RESULT_ROW_SOURCES else None

Check warning on line 590 in application/single_app/functions_generated_file_exports.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
),
)


def build_structured_artifact_rows_payload(
user_question: str,
output_format: str,
function_results: Optional[List[Dict[str, Any]]] = None,
prior_function_results_loader: Optional[Callable[[], Optional[List[Dict[str, Any]]]]] = None,
) -> Optional[Dict[str, Any]]:
"""Serialize authorized action rows when a JSON or XML reply did not carry the payload."""
normalized_output_format = str(output_format or '').strip().lower()
if normalized_output_format not in {'json', 'xml'}:
return None

function_rows = extract_authorized_function_result_rows(function_results)
row_provenance = ROW_SOURCE_CURRENT_ACTION
if not function_rows and prior_function_results_loader is not None:
function_rows = extract_authorized_function_result_rows(prior_function_results_loader())
if function_rows:
row_provenance = ROW_SOURCE_EARLIER_ACTION
if not function_rows:
return None

function_passthrough = evaluate_generated_file_passthrough_eligibility(

Check warning on line 615 in application/single_app/functions_generated_file_exports.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
user_question,
rows=function_rows,
)
if not function_passthrough.get('allowed'):

Check warning on line 619 in application/single_app/functions_generated_file_exports.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
return None

if normalized_output_format == 'json':
file_content = serialize_generated_json(function_rows)
else:
file_content = serialize_generated_xml(function_rows, root_name='GeneratedRows')
return {
'file_content': file_content,
'rows': function_rows,
'row_count': len(function_rows),
'row_source': row_provenance,
'passthrough_reason_code': function_passthrough.get('reason_code'),

Check warning on line 631 in application/single_app/functions_generated_file_exports.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
}


def extract_authorized_function_result_rows(function_results: Optional[List[Dict[str, Any]]]) -> List[Dict[str, Any]]:
Expand Down
55 changes: 47 additions & 8 deletions application/single_app/route_backend_chats.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
build_generated_file_artifact_metadata,
build_generated_file_export,
build_generated_file_output_guidance,
build_structured_artifact_rows_payload,
evaluate_generated_file_passthrough_eligibility,
estimate_function_result_row_count,
get_generated_file_export_content,
Expand Down Expand Up @@ -2633,11 +2634,26 @@
return f'Generating the {normalized_output_format} file. It will appear here when ready.'


def _build_structured_artifact_rows_payload(user_question, output_format, conversation_id, function_results):

Check warning on line 2637 in application/single_app/route_backend_chats.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
"""Fall back to authorized action rows when a JSON/XML reply carried no payload."""
return build_structured_artifact_rows_payload(
user_question,
output_format,
function_results=function_results,
prior_function_results_loader=lambda: _load_prior_turn_function_results(
get_current_user_id(),
conversation_id,

Check warning on line 2645 in application/single_app/route_backend_chats.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
settings=get_settings(),

Check warning on line 2646 in application/single_app/route_backend_chats.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
),
)


def maybe_create_assistant_file_generated_output(
user_question,
assistant_content,
conversation_id,
existing_outputs=None,
function_results=None,
):
"""Save assistant-generated JSON/XML content as a downloadable chat artifact."""
output_format = get_tabular_generated_output_format(user_question)
Expand All @@ -2650,20 +2666,40 @@

preview_items = []
preview_lines = []
row_payload = None
if output_format == 'json':
json_payload = normalize_json_artifact_payload(assistant_content)
if json_payload is None:
return None
file_content = serialize_generated_json(json_payload)
if isinstance(json_payload, list):
preview_items = json_payload[:3]
elif isinstance(json_payload, dict):
preview_items = [json_payload]
row_payload = _build_structured_artifact_rows_payload(
user_question,
output_format,
conversation_id,

Check warning on line 2676 in application/single_app/route_backend_chats.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
function_results,
)
if row_payload is None:
return None
file_content = row_payload['file_content']
preview_items = row_payload['rows'][:3]
else:
file_content = serialize_generated_json(json_payload)
if isinstance(json_payload, list):
preview_items = json_payload[:3]
elif isinstance(json_payload, dict):
preview_items = [json_payload]
else:
xml_payload = normalize_xml_artifact_payload(assistant_content)
if not xml_payload:
return None
file_content = xml_payload
row_payload = _build_structured_artifact_rows_payload(
user_question,
output_format,
conversation_id,

Check warning on line 2695 in application/single_app/route_backend_chats.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
function_results,
)
if row_payload is None:
return None
file_content = row_payload['file_content']
else:
file_content = xml_payload
preview_lines = _build_assistant_file_preview_lines(file_content)

generated_file_name = _build_assistant_file_export_name(output_format)
Expand Down Expand Up @@ -15529,6 +15565,7 @@
assistant_content=document_action_reply_content,
conversation_id=conversation_id,
existing_outputs=document_generated_analysis_artifacts + document_generated_tabular_outputs,
function_results=execution_result.get('agent_citations') or [],
)
if assistant_file_generated_output:
document_generated_analysis_artifacts.append(assistant_file_generated_output)
Expand Down Expand Up @@ -19969,6 +20006,7 @@
assistant_content=ai_message,
conversation_id=conversation_id,
existing_outputs=generated_analysis_artifacts_list + generated_tabular_outputs_list,
function_results=agent_citations_list,
)
if assistant_file_generated_output:
generated_analysis_artifacts_list.append(assistant_file_generated_output)
Expand Down Expand Up @@ -23917,6 +23955,7 @@
assistant_content=accumulated_content,
conversation_id=conversation_id,
existing_outputs=generated_analysis_artifacts_list + generated_tabular_outputs_list,
function_results=agent_citations_list,
)
if assistant_file_generated_output:
generated_analysis_artifacts_list.append(assistant_file_generated_output)
Expand Down
9 changes: 5 additions & 4 deletions functional_tests/test_assistant_table_csv_artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -1154,12 +1154,13 @@ def test_chat_route_wires_assistant_table_artifacts():
'Expected workflow model and agent execution to apply the same file-output guidance.',
)
assert_true(
chat_route_content.count('function_results=agent_citations_list') == 2,
'Expected normal and streaming Chat to pass current-turn action results to generated-file exports.',
chat_route_content.count('function_results=agent_citations_list') == 4,
'Expected normal and streaming Chat to pass current-turn action results to both the '
'generated-file export and the assistant JSON/XML export.',
)
assert_true(
'function_results=execution_result.get(\'agent_citations\') or []' in chat_route_content,
'Expected document actions to pass current-turn action results to generated-file exports.',
chat_route_content.count('function_results=execution_result.get(\'agent_citations\') or []') == 2,
'Expected document actions to pass current-turn action results to both export paths.',
)
assert_true(
'function_results=raw_agent_citations' in workflow_runner_content,
Expand Down
Loading
Loading