Compare commits

..

4 Commits

Author SHA1 Message Date
Adrian Lyjak 22e4975cb2 Refactor agent fields in llama_cloud_services (#921) 2025-09-17 15:14:40 -04:00
Peter Rowlands (변기호) bc2f04379b py: bump version to v.0.6.66 (#920) 2025-09-16 19:34:18 +09:00
Peter Rowlands (변기호) f9f951d5d8 parse: expose spreadsheet_force_formula_computation option (#919) 2025-09-16 19:28:03 +09:00
Emmanuel Ferdman 355129fea5 Fix colab broken links (#750)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2025-09-14 23:10:21 +02:00
28 changed files with 7152 additions and 4086 deletions
@@ -7,7 +7,7 @@
"source": [
"# Extraction and Analysis over a Fidelity Multi-Fund Annual Report\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services-demo/blob/main/examples/extract/asset_manager_fund_analysis.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/extract/asset_manager_fund_analysis.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"In this notebook we show you how to create an agentic document workflow over a complex document that contains annual reports for multiple funds - each fund reports financials in a standardized reporting structure, and it's all consolidated in the same document.\n",
"\n",
@@ -7,7 +7,7 @@
"source": [
"# Automotive Equity Research: A Multi-Step Agentic Workflow\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services-demo/blob/main/examples/extract/automotive_sector_analysis.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/extract/automotive_sector_analysis.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This notebook demonstrates an endtoend agentic workflow using LlamaExtract and the LlamaIndex eventdriven workflow framework for automotive sector analysis.\n",
"\n",
@@ -7,7 +7,7 @@
"source": [
"# Dynamic Section Retrieval with LlamaParse\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services-demo/blob/main/examples/parse/advanced_rag/dynamic_section_retrieval.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/parse/advanced_rag/dynamic_section_retrieval.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This notebook showcases a concept called \"dynamic section retrieval\".\n",
"\n",
+1 -1
View File
@@ -6,7 +6,7 @@
"source": [
"# Advanced RAG with LlamaParse\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/demo_advanced.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/parse/demo_advanced.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This notebook is a complete walkthrough for using LlamaParse with advanced indexing/retrieval techniques in LlamaIndex over the Apple 10K Filing. \n",
"\n",
+1 -1
View File
@@ -6,7 +6,7 @@
"source": [
"# RAG with Excel Spreadsheet using LlamaPrase\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/demo_excel.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/parse/demo_excel.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This notebook shows you using LlamaParse with Excel Spreadsheet.\n",
"\n",
+1 -1
View File
@@ -7,7 +7,7 @@
"source": [
"# Download Charts\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/demo_get_charts.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/parse/demo_get_charts.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This notebook demonstrates how to download charts from a document using the result object.\n",
"\n",
+4 -4
View File
@@ -6,7 +6,7 @@
"source": [
"# LlamaParse - Fast checking Insurance Contract for Coverage\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/demo_insurance.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/parse/demo_insurance.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"In this notebook we will look at how LlamaParse can be used to extract structured coverage information from an insurance policy.\n",
"\n",
@@ -36,7 +36,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Download an insurance policy fron IRDAI\n",
"## Download an insurance policy from IRDAI\n",
"\n",
"The Insurance Regulatory and Development Authority of India (IRDAI) maintains a great resource: https://policyholder.gov.in/web/guest/non-life-insurance-products where all insurance policies available in India are publicly available for download! Let's download a complex health insurance policy as an example."
]
@@ -228,11 +228,11 @@
" result_type=\"markdown\",\n",
" system_prompt_append=\"\"\"\n",
"This document is an insurance policy.\n",
"When a benefits/coverage/exlusion is describe in the document ammend to it add a text in the follwing benefits string format (where coverage could be an exclusion).\n",
"When a benefits/coverage/exlusion is describe in the document amend to it add a text in the following benefits string format (where coverage could be an exclusion).\n",
"\n",
"For {nameofrisk} and in this condition {whenDoesThecoverageApply} the coverage is {coverageDescription}. \n",
" \n",
"If the document contain a benefits TABLE that describe coverage amounts, do not ouput it as a table, but instead as a list of benefits string.\n",
"If the document contain a benefits TABLE that describe coverage amounts, do not output it as a table, but instead as a list of benefits string.\n",
" \n",
"\"\"\",\n",
").aparse(\"./policy.pdf\")\n",
+1 -1
View File
@@ -7,7 +7,7 @@
"source": [
"# LlamaParse `JobResult` Tour\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/demo_json.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/parse/demo_json.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"The `JobResult` object is the main object returned by the LlamaParse API. It contains all the information about the job, including the parsed data, metadata, and any errors.\n",
"\n",
+1 -1
View File
@@ -9,7 +9,7 @@
"\n",
"LlamaParse supports users to specify a `language` parameter before uploading documents, giving users better OCR capabilities over non-English PDFs, parsing images into more accurate representations.\n",
"\n",
"You can specify 80+ different languages: see this file for a full list of supported languages: https://github.com/run-llama/llama_cloud_services/blob/main/llama_parse/base.py.\n",
"You can specify 80+ different languages: see this file for a full list of supported languages: https://github.com/run-llama/llama_cloud_services/blob/main/py/llama_cloud_services/parse/base.py.\n",
"\n",
"This notebook shows a demo of this in action. \n",
"\n",
+1 -1
View File
@@ -4,7 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/excel/o1_excel_rag.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
"<a href=\"https://colab.research.google.com/github/run-llama/llama_cloud_services/blob/main/examples/parse/excel/o1_excel_rag.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
@@ -740,7 +740,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In this example, these pages aren't going to be that different when parsed, but we can verify which pages triggered auto-made by looking at the [JSON output](https://github.com/run-llama/llama_cloud_services/blob/main/examples/demo_json_tour.ipynb) of LlamaParse:"
"In this example, these pages aren't going to be that different when parsed, but we can verify which pages triggered auto-made by looking at the [JSON output](https://github.com/run-llama/llama_cloud_services/blob/main/examples/parse/demo_json_tour.ipynb) of LlamaParse:"
]
},
{
@@ -86,7 +86,7 @@ class AsyncAgentDataClient(Generic[AgentDataT]):
client=llama_client,
type=ExtractedPerson,
collection="extracted_people",
agent_url_id="person-extraction-agent"
deployment_name="person-extraction-agent"
)
# Create data
@@ -109,10 +109,12 @@ class AsyncAgentDataClient(Generic[AgentDataT]):
self,
type: Type[AgentDataT],
collection: str = "default",
agent_url_id: Optional[str] = None,
deployment_name: Optional[str] = None,
client: Optional[AsyncLlamaCloud] = None,
token: Optional[str] = None,
base_url: Optional[str] = None,
# deprecated, use deployment_name instead
agent_url_id: Optional[str] = None,
):
"""
Initialize the AsyncAgentDataClient.
@@ -123,11 +125,11 @@ class AsyncAgentDataClient(Generic[AgentDataT]):
collection: Named collection within the agent for organizing data.
Defaults to "default". Collections allow logical separation of
different data types or workflows within the same agent.
agent_url_id: Unique identifier for the agent. This normally appears in the
url of an agent within the llama cloud platform. If not provided,
will attempt to use the LLAMA_DEPLOY_DEPLOYMENT_NAME environment
variable. Data can only be added to an already existing agent in the
platform.
deployment_name: Unique identifier for the agent deployment. This normally
appears in the URL of an agent within the Llama Cloud platform. If not
provided, will attempt to use the LLAMA_DEPLOY_DEPLOYMENT_NAME
environment variable. Data can only be added to an already existing
agent in the platform.
client: AsyncLlamaCloud client instance for API communication. If not provided, will
construct one from the provided api token and base url
token: Llama Cloud API token. Reads from LLAMA_CLOUD_API_KEY if not provided
@@ -135,15 +137,14 @@ class AsyncAgentDataClient(Generic[AgentDataT]):
defaults to https://api.cloud.llamaindex.ai
Raises:
ValueError: If agent_url_id is not provided and the
ValueError: If deployment_name is not provided and the
LLAMA_DEPLOY_DEPLOYMENT_NAME environment variable is not set
Note:
The client automatically applies retry logic to all API calls with
exponential backoff for timeout, connection, and HTTP status errors.
"""
self.agent_url_id = agent_url_id or get_default_agent_id()
self.deployment_name = deployment_name or agent_url_id or get_default_agent_id()
self.collection = collection
if not client:
@@ -164,7 +165,7 @@ class AsyncAgentDataClient(Generic[AgentDataT]):
@agent_data_retry
async def create_item(self, data: AgentDataT) -> TypedAgentData[AgentDataT]:
raw_data = await self.client.beta.create_agent_data(
agent_slug=self.agent_url_id,
deployment_name=self.deployment_name,
collection=self.collection,
data=data.model_dump(),
)
@@ -211,7 +212,7 @@ class AsyncAgentDataClient(Generic[AgentDataT]):
include_total: Whether to include the total count in the response. Defaults to False to improve performance. It's recommended to only request on the first page.
"""
raw = await self.client.beta.search_agent_data_api_v_1_beta_agent_data_search_post(
agent_slug=self.agent_url_id,
deployment_name=self.deployment_name,
collection=self.collection,
filter=filter,
order_by=order_by,
@@ -254,7 +255,7 @@ class AsyncAgentDataClient(Generic[AgentDataT]):
page_size: Maximum number of groups to return per page.
"""
raw = await self.client.beta.aggregate_agent_data_api_v_1_beta_agent_data_aggregate_post(
agent_slug=self.agent_url_id,
deployment_name=self.deployment_name,
collection=self.collection,
page_size=page_size,
filter=filter,
@@ -10,7 +10,7 @@ CRUD operations, search capabilities, filtering, and aggregation functionality
for managing agent-generated data at scale.
Key Concepts:
- Agent Slug: Unique identifier for an agent instance
- Deployment Name: Unique identifier for an agent deployment
- Collection: Named grouping of data within an agent (defaults to "default"). Data within a collection should be of the same type.
- Agent Data: Individual structured data records with metadata and timestamps
@@ -26,7 +26,7 @@ Example Usage:
client=async_llama_cloud,
type=Person,
collection="people",
agent_url_id="my-extraction-agent-xyz"
deployment_name="my-extraction-agent-xyz"
)
# Create typed data
@@ -78,7 +78,7 @@ class TypedAgentData(BaseModel, Generic[AgentDataT]):
Attributes:
id: Unique identifier for this data record
agent_url_id: Identifier of the agent that created this data
deployment_name: Identifier of the agent deployment that created this data
collection: Named collection within the agent (used for organization)
data: The actual structured data payload (typed as AgentDataT)
created_at: Timestamp when the record was first created
@@ -94,8 +94,8 @@ class TypedAgentData(BaseModel, Generic[AgentDataT]):
"""
id: Optional[str] = Field(description="Unique identifier for this data record")
agent_url_id: str = Field(
description="Identifier of the agent that created this data"
deployment_name: str = Field(
description="Identifier of the agent deployment that created this data"
)
collection: Optional[str] = Field(
description="Named collection within the agent for data organization"
@@ -124,7 +124,7 @@ class TypedAgentData(BaseModel, Generic[AgentDataT]):
return cls(
id=raw_data.id,
agent_url_id=raw_data.agent_slug,
deployment_name=raw_data.deployment_name,
collection=raw_data.collection,
data=data,
created_at=raw_data.created_at,
+40 -94
View File
@@ -420,6 +420,10 @@ class LlamaParse(BasePydanticReader):
default=False,
description="If set to true, the parser will extract sub-tables from the spreadsheet when possible (more than one table per sheet).",
)
spreadsheet_force_formula_computation: Optional[bool] = Field(
default=False,
description="If set to true, the parser will re-compute values for all spreadsheet cells containing formulas.",
)
specialized_chart_parsing_agentic: Optional[bool] = Field(
default=False,
description="If set to true, the parser will use a specialized agentic chart parsing model to extract data from charts. This model is able to understand the chart type and extract the data accordingly.",
@@ -965,6 +969,11 @@ class LlamaParse(BasePydanticReader):
if self.spreadsheet_extract_sub_tables:
data["spreadsheet_extract_sub_tables"] = self.spreadsheet_extract_sub_tables
if self.spreadsheet_force_formula_computation:
data[
"spreadsheet_force_formula_computation"
] = self.spreadsheet_force_formula_computation
if self.specialized_chart_parsing_agentic:
data[
"specialized_chart_parsing_agentic"
@@ -1073,11 +1082,7 @@ class LlamaParse(BasePydanticReader):
return current_interval # Default fallback
async def _get_job_result(
self,
job_id: str,
result_type: str,
verbose: bool = False,
raise_job_error: bool = True,
self, job_id: str, result_type: str, verbose: bool = False
) -> Dict[str, Any]:
start = time.time()
tries = 0
@@ -1110,25 +1115,7 @@ class LlamaParse(BasePydanticReader):
print(".", end="", flush=True)
current_interval = self._calculate_backoff(current_interval)
else:
if raise_job_error:
raise JobFailedException.from_result(result_json)
else:
error_code = result_json.get("error_code")
error_message = result_json.get("error_message")
error_parts = [f"Job ID: {job_id} failed with status: {status}"]
if error_code:
error_parts.append(f"Error code: {error_code}")
if error_message:
error_parts.append(f"Error message: {error_message}")
error_str = ", ".join(error_parts)
return {
"pages": [],
"job_metadata": {"job_pages": 0},
"error": error_str,
"status": status,
}
raise JobFailedException.from_result(result_json)
except (
httpx.ConnectError,
httpx.ReadError,
@@ -1159,7 +1146,6 @@ class LlamaParse(BasePydanticReader):
fs: Optional[AbstractFileSystem] = None,
result_type: Optional[str] = None,
num_workers: Optional[int] = None,
raise_job_error: bool = True,
) -> List[Tuple[str, Dict[str, Any]]]:
if self.partition_pages is None:
job_results = [
@@ -1168,7 +1154,6 @@ class LlamaParse(BasePydanticReader):
extra_info=extra_info,
fs=fs,
result_type=result_type,
raise_job_error=raise_job_error,
)
]
else:
@@ -1178,7 +1163,6 @@ class LlamaParse(BasePydanticReader):
fs=fs,
result_type=result_type,
num_workers=num_workers,
raise_job_error=raise_job_error,
)
return job_results
@@ -1188,7 +1172,6 @@ class LlamaParse(BasePydanticReader):
extra_info: Optional[dict] = None,
fs: Optional[AbstractFileSystem] = None,
result_type: Optional[str] = None,
raise_job_error: bool = True,
**create_kwargs: Any,
) -> Tuple[str, Dict[str, Any]]:
"""Create one parse job and wait for the result."""
@@ -1198,10 +1181,7 @@ class LlamaParse(BasePydanticReader):
if self.verbose:
print("Started parsing the file under job_id %s" % job_id)
result = await self._get_job_result(
job_id,
result_type or self.result_type.value,
verbose=self.verbose,
raise_job_error=raise_job_error,
job_id, result_type or self.result_type.value, verbose=self.verbose
)
return job_id, result
@@ -1212,7 +1192,6 @@ class LlamaParse(BasePydanticReader):
fs: Optional[AbstractFileSystem] = None,
result_type: Optional[str] = None,
num_workers: Optional[int] = None,
raise_job_error: bool = True,
) -> List[Tuple[str, Dict[str, Any]]]:
"""Partition a file and run separate parse jobs per partition segment."""
assert self.partition_pages is not None
@@ -1227,7 +1206,6 @@ class LlamaParse(BasePydanticReader):
extra_info=extra_info,
fs=fs,
result_type=result_type,
raise_job_error=raise_job_error,
partition_target_pages=target_pages,
)
for target_pages in partition_pages(
@@ -1255,33 +1233,28 @@ class LlamaParse(BasePydanticReader):
size = self.partition_pages
if not size:
break
# Fetch JSON result type first to get accurate pagination data
# and then fetch the user's desired result type if needed
job_id, json_result = await self._parse_one_unpartitioned(
file_path,
extra_info=extra_info,
fs=fs,
result_type=ResultType.JSON.value,
raise_job_error=raise_job_error,
partition_target_pages=f"{total}-{total + size - 1}",
)
if json_result.get("error"):
if results and "NO_DATA_FOUND_IN_FILE" in json_result.get("error", ""):
return results
results.append((job_id, json_result))
return results
result_type = result_type or self.result_type.value
if result_type == ResultType.JSON.value:
job_result = json_result
else:
job_result = await self._get_job_result(
job_id,
result_type,
verbose=self.verbose,
raise_job_error=raise_job_error,
try:
# Fetch JSON result type first to get accurate pagination data
# and then fetch the user's desired result type if needed
job_id, json_result = await self._parse_one_unpartitioned(
file_path,
extra_info=extra_info,
fs=fs,
result_type=ResultType.JSON.value,
partition_target_pages=f"{total}-{total + size - 1}",
)
result_type = result_type or self.result_type.value
if result_type == ResultType.JSON.value:
job_result = json_result
else:
job_result = await self._get_job_result(
job_id, result_type, verbose=self.verbose
)
except JobFailedException as e:
if results and e.error_code == "NO_DATA_FOUND_IN_FILE":
# Expected when we try to read past the end of the file
return results
raise
results.append((job_id, job_result))
if len(json_result["pages"]) < size:
break
@@ -1395,7 +1368,6 @@ class LlamaParse(BasePydanticReader):
extra_info: Optional[dict] = None,
fs: Optional[AbstractFileSystem] = None,
num_workers: Optional[int] = None,
raise_job_error: bool = True,
) -> List[JobResult]:
job_results = await self._parse_one(
file_path,
@@ -1403,7 +1375,6 @@ class LlamaParse(BasePydanticReader):
fs=fs,
result_type=ResultType.JSON.value,
num_workers=num_workers,
raise_job_error=raise_job_error,
)
return [
JobResult(
@@ -1423,7 +1394,6 @@ class LlamaParse(BasePydanticReader):
file_path: Union[List[FileInput], FileInput],
extra_info: Optional[dict] = None,
fs: Optional[AbstractFileSystem] = None,
raise_job_error: bool = True,
) -> Union[List["JobResult"], "JobResult"]:
"""
Parse the file and return a JobResult object instead of Document objects.
@@ -1435,7 +1405,6 @@ class LlamaParse(BasePydanticReader):
file_path: Path to the file to parse. Can be a string, path, bytes, file-like object, or a list of these.
extra_info: Additional metadata to include in the result.
fs: Optional filesystem to use for reading files.
raise_job_error: If True (default), raises JobFailedException when jobs fail. If False, returns JobResult objects with error information.
Returns:
JobResult object or list of JobResult objects if either multiple files were provided or file(s) were partitioned before parsing.
@@ -1451,11 +1420,7 @@ class LlamaParse(BasePydanticReader):
else:
file_name = str(file_path)
result = await self._aparse_one(
file_path,
file_name,
extra_info=extra_info,
fs=fs,
raise_job_error=raise_job_error,
file_path, file_name, extra_info=extra_info, fs=fs
)
return result[0] if len(result) == 1 else result
@@ -1481,7 +1446,6 @@ class LlamaParse(BasePydanticReader):
extra_info=extra_info,
fs=fs,
num_workers=1,
raise_job_error=raise_job_error,
)
for i, f in enumerate(file_path)
],
@@ -1507,7 +1471,6 @@ class LlamaParse(BasePydanticReader):
file_path: Union[List[FileInput], FileInput],
extra_info: Optional[dict] = None,
fs: Optional[AbstractFileSystem] = None,
raise_job_error: bool = True,
) -> Union[List["JobResult"], "JobResult"]:
"""
Parse the file and return a JobResult object instead of Document objects.
@@ -1519,17 +1482,12 @@ class LlamaParse(BasePydanticReader):
file_path: Path to the file to parse. Can be a string, path, bytes, file-like object, or a list of these.
extra_info: Additional metadata to include in the result.
fs: Optional filesystem to use for reading files.
raise_job_error: If True (default), raises JobFailedException when jobs fail. If False, returns JobResult objects with error information.
Returns:
JobResult object or list of JobResult objects if multiple files were provided
"""
try:
return asyncio_run(
self.aparse(
file_path, extra_info, fs=fs, raise_job_error=raise_job_error
)
)
return asyncio_run(self.aparse(file_path, extra_info, fs=fs))
except RuntimeError as e:
if nest_asyncio_err in str(e):
raise RuntimeError(nest_asyncio_msg)
@@ -1796,7 +1754,7 @@ class LlamaParse(BasePydanticReader):
return sub_docs
async def aget_result(
self, job_id: Union[str, List[str]], raise_job_error: bool = True
self, job_id: Union[str, List[str]]
) -> Union[JobResult, List[JobResult]]:
"""
Return JobResult object for previously parsed job(s).
@@ -1805,17 +1763,13 @@ class LlamaParse(BasePydanticReader):
Args:
job_id: Job ID or list of multiple Job IDs to be retrieved.
raise_job_error: If True (default), raises JobFailedException when jobs fail. If False, returns JobResult objects with error information.
Returns:
JobResult object or list of JobResult objects if multiple job IDs were provided.
"""
if isinstance(job_id, str):
result = await self._get_job_result(
job_id,
ResultType.JSON.value,
verbose=self.verbose,
raise_job_error=raise_job_error,
job_id, ResultType.JSON.value, verbose=self.verbose
)
return JobResult(
job_id=job_id,
@@ -1829,12 +1783,7 @@ class LlamaParse(BasePydanticReader):
elif isinstance(job_id, list):
results = []
jobs = [
self._get_job_result(
id_,
ResultType.JSON.value,
verbose=self.verbose,
raise_job_error=raise_job_error,
)
self._get_job_result(id_, ResultType.JSON.value, verbose=self.verbose)
for id_ in job_id
]
results = await run_jobs(
@@ -1859,7 +1808,7 @@ class LlamaParse(BasePydanticReader):
raise ValueError("The input job_id must be a string or a list of strings.")
def get_result(
self, job_id: Union[str, List[str]], raise_job_error: bool = True
self, job_id: Union[str, List[str]]
) -> Union[JobResult, List[JobResult]]:
"""
Return JobResult object for previously parsed job(s).
@@ -1868,15 +1817,12 @@ class LlamaParse(BasePydanticReader):
Args:
job_id: Job ID or list of multiple Job IDs to be retrieved.
raise_job_error: If True (default), raises JobFailedException when jobs fail. If False, returns JobResult objects with error information.
Returns:
JobResult object or list of JobResult objects if multiple job IDs were provided.
"""
try:
return asyncio_run(
self.aget_result(job_id, raise_job_error=raise_job_error)
)
return asyncio_run(self.aget_result(job_id))
except RuntimeError as e:
if nest_asyncio_err in str(e):
raise RuntimeError(nest_asyncio_msg)
+2 -2
View File
@@ -11,13 +11,13 @@ dev = [
[project]
name = "llama-parse"
version = "0.6.65"
version = "0.6.67"
description = "Parse files into RAG-Optimized formats."
authors = [{name = "Logan Markewich", email = "logan@llamaindex.ai"}]
requires-python = ">=3.9,<4.0"
readme = "README.md"
license = "MIT"
dependencies = ["llama-cloud-services>=0.6.64"]
dependencies = ["llama-cloud-services>=0.6.67"]
[project.scripts]
llama-parse = "llama_parse.cli.main:parse"
+2 -2
View File
@@ -19,7 +19,7 @@ dev = [
[project]
name = "llama-cloud-services"
version = "0.6.65"
version = "0.6.67"
description = "Tailored SDK clients for LlamaCloud services."
authors = [{name = "Logan Markewich", email = "logan@runllama.ai"}]
requires-python = ">=3.9,<4.0"
@@ -27,7 +27,7 @@ readme = "README.md"
license = "MIT"
dependencies = [
"llama-index-core>=0.12.0",
"llama-cloud==0.1.41",
"llama-cloud==0.1.42",
"pydantic>=2.8,!=2.10",
"click>=8.1.7,<9",
"python-dotenv>=1.0.1,<2",
@@ -68,7 +68,7 @@ async def test_agent_data_crud_operations():
client=client,
type=ExampleData,
collection=f"test-collection-{test_id[:8]}",
agent_url_id=LLAMA_DEPLOY_DEPLOYMENT_NAME,
deployment_name=LLAMA_DEPLOY_DEPLOYMENT_NAME,
)
# Create test data
-196
View File
@@ -2,7 +2,6 @@ import os
import pytest
import shutil
from typing import Optional, cast
from unittest.mock import patch
from fsspec.implementations.local import LocalFileSystem
from httpx import AsyncClient
@@ -205,10 +204,6 @@ async def test_get_result(markdown_parser: LlamaParse) -> None:
assert len(result.pages) == len(expected.pages)
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
@pytest.mark.asyncio
async def test_parse_audio() -> None:
parser = LlamaParse()
@@ -216,194 +211,3 @@ async def test_parse_audio() -> None:
result = await parser.aparse(filepath)
assert result.job_id is not None
@pytest.mark.asyncio
async def test_error_handling_with_raise_job_error_false() -> None:
"""Test that failed jobs return JobResult objects with error information when raise_job_error=False."""
parser = LlamaParse(api_key="test_key")
# Mock error result with full error information
mock_error_result = {
"pages": [],
"job_metadata": {"job_pages": 0},
"error": "Job ID: test_job_123 failed with status: ERROR, Error code: INVALID_FILE, Error message: File format not supported",
"status": "ERROR",
}
with patch.object(parser, "_create_job", return_value="test_job_123"), patch.object(
parser, "_get_job_result", return_value=mock_error_result
):
# Test aparse with raise_job_error=False
result = await parser.aparse("test_file.txt", raise_job_error=False)
assert isinstance(result, type(result)) # Check it's a JobResult
assert result.job_id == "test_job_123"
assert result.error is not None
assert "ERROR" in result.error
assert "INVALID_FILE" in result.error
assert "File format not supported" in result.error
assert len(result.pages) == 0
# Test parse (synchronous version) with raise_job_error=False
result_sync = parser.parse("test_file.txt", raise_job_error=False)
assert isinstance(result_sync, type(result_sync))
assert result_sync.job_id == "test_job_123"
assert result_sync.error is not None
assert "INVALID_FILE" in result_sync.error
assert "File format not supported" in result_sync.error
@pytest.mark.asyncio
async def test_error_handling_with_raise_job_error_true() -> None:
"""Test that failed jobs raise JobFailedException when raise_job_error=True (default behavior)."""
parser = LlamaParse(api_key="test_key")
# Mock that _get_job_result will raise JobFailedException when raise_job_error=True
from llama_cloud_services.parse.base import JobFailedException
def mock_get_job_result(job_id, result_type, verbose=False, raise_job_error=True):
if raise_job_error:
raise JobFailedException(
"test_job_123",
"ERROR",
error_code="INVALID_FILE",
error_message="File format not supported",
)
else:
return {
"pages": [],
"job_metadata": {"job_pages": 0},
"error": "Job ID: test_job_123 failed with status: ERROR, Error code: INVALID_FILE, Error message: File format not supported",
"status": "ERROR",
}
with patch.object(parser, "_create_job", return_value="test_job_123"), patch.object(
parser, "_get_job_result", side_effect=mock_get_job_result
):
# Test aparse with raise_job_error=True (default) - should raise exception
with pytest.raises(JobFailedException) as exc_info:
await parser.aparse("test_file.txt")
assert exc_info.value.job_id == "test_job_123"
assert exc_info.value.status == "ERROR"
assert exc_info.value.error_code == "INVALID_FILE"
# Test parse (synchronous version) with raise_job_error=True (default) - should raise exception
with pytest.raises(JobFailedException) as exc_info:
parser.parse("test_file.txt")
assert exc_info.value.job_id == "test_job_123"
assert exc_info.value.status == "ERROR"
@pytest.mark.asyncio
async def test_error_handling_with_minimal_fields() -> None:
"""Test error handling when only status is available (no error_code/error_message) with raise_job_error=False."""
parser = LlamaParse(api_key="test_key")
# Mock error result with minimal fields (only what's guaranteed)
mock_minimal_error_result = {
"pages": [],
"job_metadata": {"job_pages": 0},
"error": "Job ID: test_job_456 failed with status: CANCELED",
"status": "CANCELED",
}
with patch.object(parser, "_create_job", return_value="test_job_456"), patch.object(
parser, "_get_job_result", return_value=mock_minimal_error_result
):
# Test aparse with a minimal error response and raise_job_error=False
result = await parser.aparse("test_file.txt", raise_job_error=False)
assert isinstance(result, type(result))
assert result.job_id == "test_job_456"
assert result.error is not None
assert "CANCELED" in result.error
assert len(result.pages) == 0
@pytest.mark.asyncio
async def test_successful_job_still_works() -> None:
"""Test that successful jobs still work as before after error handling changes."""
parser = LlamaParse(api_key="test_key")
# Mock successful result
mock_success_result = {
"pages": [
{
"page": 0,
"text": "Sample text content",
"md": "# Sample markdown content",
"images": [],
"charts": [],
"tables": [],
"layout": [],
"items": [],
"status": "SUCCESS",
"links": [],
"width": 612.0,
"height": 792.0,
}
],
"job_metadata": {"job_pages": 1},
}
with patch.object(
parser, "_create_job", return_value="success_job_456"
), patch.object(parser, "_get_job_result", return_value=mock_success_result):
# Test aparse with a successful job (both with and without raise_job_error parameter)
result = await parser.aparse("test_file.txt")
assert isinstance(result, type(result))
assert result.job_id == "success_job_456"
assert result.error is None # No error for successful jobs
assert len(result.pages) == 1
assert result.pages[0].text == "Sample text content"
# Test with explicit raise_job_error=False (should work the same for successful jobs)
result2 = await parser.aparse("test_file.txt", raise_job_error=False)
assert isinstance(result2, type(result2))
assert result2.job_id == "success_job_456"
assert result2.error is None
assert len(result2.pages) == 1
assert result2.pages[0].text == "Sample text content"
@pytest.mark.asyncio
async def test_get_result_with_raise_job_error_parameter() -> None:
"""Test that get_result method respects the raise_job_error parameter."""
parser = LlamaParse(api_key="test_key")
# Mock error result
mock_error_result = {
"pages": [],
"job_metadata": {"job_pages": 0},
"error": "Job ID: test_job_789 failed with status: ERROR, Error code: TIMEOUT, Error message: Job timed out",
"status": "ERROR",
}
with patch.object(parser, "_get_job_result", return_value=mock_error_result):
# Test aget_result with raise_job_error=False
result = await parser.aget_result("test_job_789", raise_job_error=False)
assert isinstance(result, type(result))
assert result.job_id == "test_job_789"
assert result.error is not None
assert "TIMEOUT" in result.error
assert len(result.pages) == 0
# Test get_result (synchronous version) with raise_job_error=False
result_sync = parser.get_result("test_job_789", raise_job_error=False)
assert isinstance(result_sync, type(result_sync))
assert result_sync.job_id == "test_job_789"
assert result_sync.error is not None
assert "TIMEOUT" in result_sync.error
@@ -38,7 +38,7 @@ def test_typed_agent_data_from_raw():
"""Test TypedAgentData.from_raw class method."""
raw_data = AgentData(
id="456",
agent_slug="extraction-agent",
deployment_name="extraction-agent",
collection="employees",
data={"name": "Jane Smith", "age": 25, "email": "jane@company.com"},
created_at=datetime.now(),
@@ -48,7 +48,7 @@ def test_typed_agent_data_from_raw():
typed_data = TypedAgentData.from_raw(raw_data, Person)
assert typed_data.id == "456"
assert typed_data.agent_url_id == "extraction-agent"
assert typed_data.deployment_name == "extraction-agent"
assert typed_data.collection == "employees"
assert typed_data.data.name == "Jane Smith"
assert typed_data.data.age == 25
@@ -59,7 +59,7 @@ def test_typed_agent_data_from_raw_validation_error():
"""Test TypedAgentData.from_raw with invalid data."""
raw_data = AgentData(
id="789",
agent_slug="test-agent",
deployment_name="test-agent",
collection="people",
data={"name": "Invalid Person", "age": "not_a_number"}, # Invalid age
created_at=datetime.now(),
Generated
+5 -5
View File
@@ -1582,21 +1582,21 @@ wheels = [
[[package]]
name = "llama-cloud"
version = "0.1.41"
version = "0.1.42"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "httpx" },
{ name = "pydantic" },
]
sdist = { url = "https://files.pythonhosted.org/packages/62/6c/b2e84eebed376aea34c446cab745da5fc4e9dc53309180672299083219d5/llama_cloud-0.1.41.tar.gz", hash = "sha256:dcb741b779e3e740cd64928cfffc8ef70ed0e9bae9ef26acbe1d7e32aa737bdc", size = 109854, upload-time = "2025-09-05T22:45:13.069Z" }
sdist = { url = "https://files.pythonhosted.org/packages/21/04/ae0694b582d6aab4d6e7957febb7bff048897ac231ad80ba1bd71547d944/llama_cloud-0.1.42.tar.gz", hash = "sha256:485aa0e364ea648e3aaa3b2c54af7bcb6f2242c50b4f86ec022e137413fff464", size = 112480, upload-time = "2025-09-16T20:25:42.631Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/4d/f0af76b389310840ce3483a92560a152025b0eefe4eee0c81102bf3317e6/llama_cloud-0.1.41-py3-none-any.whl", hash = "sha256:c847f288f0d3f4b23f47345088006deae5f2cf3f223ac1819d4c1531e9aaa13e", size = 307646, upload-time = "2025-09-05T22:45:11.597Z" },
{ url = "https://files.pythonhosted.org/packages/6a/61/85d115699a59d03f0783e119aaf6d534fca95dbe1a4531a8056e6a4774ed/llama_cloud-0.1.42-py3-none-any.whl", hash = "sha256:4ed3edde4a277ff52eeb831188c8476eb079b5e4605ad3142157a0f054b27d96", size = 311857, upload-time = "2025-09-16T20:25:41.479Z" },
]
[[package]]
name = "llama-cloud-services"
version = "0.6.65"
version = "0.6.66"
source = { editable = "." }
dependencies = [
{ name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
@@ -1631,7 +1631,7 @@ dev = [
requires-dist = [
{ name = "click", specifier = ">=8.1.7,<9" },
{ name = "eval-type-backport", marker = "python_full_version < '3.10'", specifier = ">=0.2.0,<0.3" },
{ name = "llama-cloud", specifier = "==0.1.41" },
{ name = "llama-cloud", specifier = "==0.1.42" },
{ name = "llama-index-core", specifier = ">=0.12.0" },
{ name = "packaging", specifier = ">=25.0" },
{ name = "platformdirs", specifier = ">=4.3.7,<5" },
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "llama-cloud-services",
"version": "0.3.5",
"version": "0.3.6",
"type": "module",
"license": "MIT",
"scripts": {
@@ -25,20 +25,23 @@ import type {
export class AgentClient<T = unknown> {
private client: ReturnType<typeof createClient>;
private collection: string;
private agentUrlId: string;
private deploymentName: string;
constructor({
client = defaultClient,
collection = "default",
agentUrlId = "_public",
deploymentName = "_public",
agentUrlId,
}: {
client?: ReturnType<typeof createClient>;
collection?: string;
deploymentName?: string;
// deprecated, use deploymentName instead
agentUrlId?: string;
}) {
this.client = client;
this.collection = collection;
this.agentUrlId = agentUrlId;
this.deploymentName = agentUrlId || deploymentName;
}
/**
@@ -48,7 +51,7 @@ export class AgentClient<T = unknown> {
const response = await createAgentDataApiV1BetaAgentDataPost({
throwOnError: true,
body: {
agent_slug: this.agentUrlId,
deployment_name: this.deploymentName,
collection: this.collection,
data: data as Record<string, unknown>,
},
@@ -118,7 +121,7 @@ export class AgentClient<T = unknown> {
const response = await searchAgentDataApiV1BetaAgentDataSearchPost({
throwOnError: true,
body: {
agent_slug: this.agentUrlId,
deployment_name: this.deploymentName,
...(this.collection !== undefined && {
collection: this.collection,
}),
@@ -165,7 +168,7 @@ export class AgentClient<T = unknown> {
const response = await aggregateAgentDataApiV1BetaAgentDataAggregatePost({
throwOnError: true,
body: {
agent_slug: this.agentUrlId,
deployment_name: this.deploymentName,
...(this.collection !== undefined && {
collection: this.collection,
}),
@@ -209,7 +212,7 @@ export class AgentClient<T = unknown> {
private transformResponse(data: AgentData): TypedAgentData<T> {
const result: TypedAgentData<T> = {
id: data.id!,
agentUrlId: data.agent_slug,
deploymentName: data.deployment_name,
data: data.data as T,
createdAt: new Date(data.created_at!),
updatedAt: new Date(data.updated_at!),
@@ -250,10 +253,10 @@ export interface AgentDataClientOptions {
/** Base URL for the client */
/** Base URL of the llama cloud api */
baseUrl?: string;
/** If running in an agent runtime, optionally provide the window url to infer the agent url id */
/** If running in an agent runtime, optionally provide the window url to infer the deployment name */
windowUrl?: string;
/** Agent URL ID for the client, if not provided, it will be inferred from the window url, or fall back to "default" */
agentUrlId?: string;
/** Deployment name for the client, if not provided, it will be inferred from the window url, or fall back to "default" */
deploymentName?: string;
/** Collection name for the client, defaults to "default" */
collection?: string;
}
@@ -267,22 +270,25 @@ export function createAgentDataClient<T = unknown>({
client = defaultClient,
windowUrl,
env,
deploymentName,
agentUrlId,
collection = "default",
}: {
client?: ReturnType<typeof createClient>;
windowUrl?: string;
env?: Record<string, string>;
deploymentName?: string;
// deprecated, use deploymentName instead
agentUrlId?: string;
collection?: string;
} = {}): AgentClient<T> {
if (env && !agentUrlId) {
agentUrlId =
if (env && !deploymentName) {
deploymentName =
env.LLAMA_DEPLOY_DEPLOYMENT_NAME ||
env.NEXT_PUBLIC_LLAMA_DEPLOY_DEPLOYMENT_NAME ||
env.VITE_LLAMA_DEPLOY_DEPLOYMENT_NAME;
}
if (windowUrl && !agentUrlId) {
if (windowUrl && !deploymentName) {
try {
const url = new URL(windowUrl);
const path = url.pathname;
@@ -291,17 +297,18 @@ export function createAgentDataClient<T = unknown>({
url.hostname.includes("127.0.0.1");
if (path.startsWith("/deployments/") && !isLocalhost) {
// /deployments/<agent-url-id>/ui/ -> ["", "deployments", "<agent-url-id>", "ui"]
agentUrlId = path.split("/")[2];
deploymentName = path.split("/")[2];
}
} catch (error) {
console.warn(
"Failed to infer agent url id from window url, falling back to default",
"Failed to infer deployment name from window url, falling back to default",
error,
);
}
}
return new AgentClient({
...(deploymentName && { deploymentName }),
...(agentUrlId && { agentUrlId }),
collection,
client,
@@ -87,8 +87,8 @@ export interface ExtractedData<T = unknown> {
export interface TypedAgentData<T = unknown> {
/** The unique ID of the agent data record. */
id: string;
/** The ID of the agent that created the data. */
agentUrlId: string;
/** The deployment name of the agent that created the data. */
deploymentName: string;
/** The collection of the agent data. */
collection?: string;
/** The data of the agent data. Usually an ExtractedData&lt;SomeOtherType&gt; */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff