Compare commits

...

3 Commits

Author SHA1 Message Date
Adrian Lyjak 71f30242eb include total 2025-07-12 01:34:11 -04:00
Adrian Lyjak f6447bbb49 fix docs build for agent data 2025-07-11 23:17:35 -04:00
Adrian Lyjak 9b0477f268 Adjust agent data types
- Updates ExtractedData to match python type declarations
- Updates client interface to more closely align python implementation
- Updates some incorrect types
- Removes agent-data/extract API. That isn't an existing thing
- Move to beta namespace to reflect instability
2025-07-11 21:19:13 +00:00
13 changed files with 474 additions and 407 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@llamaindex/cloud": patch
---
Bug fixes for new beta agent-data cloud API
@@ -21,7 +21,7 @@ Where as the `llamaindex` package is working with Next.js, some provider package
Make sure to use `withLlamaIndex` to make sure that LlamaIndex.TS works well with Next.js.
```js
```javascript
// next.config.mjs / next.config.ts
import withLlamaIndex from "llamaindex/next";
@@ -15,7 +15,7 @@ npm i @langtrase/typescript-sdk
## Initialize
```js
```javascript
import * as Langtrace from "@langtrase/typescript-sdk";
Langtrace.init({ api_key: "<YOUR_API_KEY>" });
```
@@ -12,7 +12,7 @@ LLM applications. It connects to [all major observability platforms](https://www
npm i @traceloop/node-server-sdk
```
```js
```javascript
import * as traceloop from "@traceloop/node-server-sdk";
traceloop.initialize({
@@ -175,7 +175,7 @@ Try it out ⬇️
And also update the `next.config.js` to make `@llamaindex/env` work properly.
```js
```javascript
const config = {
webpack: (config) => {
if (Array.isArray(config.target) && config.target.includes('web')) {
+1
View File
@@ -6,6 +6,7 @@
],
"exclude": [
"../../packages/autotool/**/src/index.ts",
"../../packages/cloud/src/beta/**",
"**/node_modules/**",
"**/dist/**",
"**/test/**",
+7 -7
View File
@@ -13,20 +13,20 @@
"./api",
"./reader",
"./parse",
"./agent"
"./beta/agent"
],
"exports": {
"./openapi.json": "./openapi.json",
"./agent": {
"./beta/agent": {
"require": {
"types": "./agent/dist/index.d.cts",
"default": "./agent/dist/index.cjs"
"types": "./beta/agent/dist/index.d.cts",
"default": "./beta/agent/dist/index.cjs"
},
"import": {
"types": "./agent/dist/index.d.ts",
"default": "./agent/dist/index.js"
"types": "./beta/agent/dist/index.d.ts",
"default": "./beta/agent/dist/index.js"
},
"default": "./agent/dist/index.js"
"default": "./beta/agent/dist/index.js"
},
"./api": {
"require": {
-291
View File
@@ -1,291 +0,0 @@
import { createClient, createConfig } from "@hey-api/client-fetch";
import { getEnv } from "@llamaindex/env";
import pRetry from "p-retry";
import {
createAgentDataApiV1BetaAgentDataPost,
deleteAgentDataApiV1BetaAgentDataItemIdDelete,
getAgentDataApiV1BetaAgentDataItemIdGet,
searchAgentDataApiV1BetaAgentDataSearchPost,
updateAgentDataApiV1BetaAgentDataItemIdPut,
type AgentData,
} from "../client";
import type {
CreateAgentDataOptions,
ExtractedData,
ExtractOptions,
ListAgentDataOptions,
TypedAgentData,
TypedAgentDataItems,
UpdateAgentDataOptions,
} from "./types";
/**
* Async client for agent data operations
*/
export class AgentClient {
private client: ReturnType<typeof createClient>;
private baseUrl: string;
private headers: Record<string, string>;
constructor(options?: { apiKey?: string; baseUrl?: string }) {
const apiKey = options?.apiKey || getEnv("LLAMA_CLOUD_API_KEY");
this.baseUrl = options?.baseUrl || "https://api.cloud.llamaindex.ai/";
this.headers = {
"X-SDK-Name": "llamaindex-ts",
...(apiKey && { Authorization: `Bearer ${apiKey}` }),
};
this.client = createClient(
createConfig({
baseUrl: this.baseUrl,
headers: this.headers,
}),
);
}
/**
* Create new agent data
*/
async create<T = unknown>(
options: CreateAgentDataOptions<T>,
): Promise<TypedAgentData<T>> {
const response = await createAgentDataApiV1BetaAgentDataPost({
throwOnError: true,
body: {
agent_slug: options.agentSlug,
...(options.collection !== undefined && {
collection: options.collection,
}),
data: options.data as Record<string, unknown>,
},
client: this.client,
});
return this.transformResponse(response.data);
}
/**
* Get agent data by ID
*/
async get<T = unknown>(id: string): Promise<TypedAgentData<T> | null> {
try {
const response = await getAgentDataApiV1BetaAgentDataItemIdGet({
throwOnError: true,
path: { item_id: id },
client: this.client,
});
return this.transformResponse(response.data);
} catch (error) {
if (
error instanceof Error &&
"response" in error &&
(error as { response?: { status?: number } }).response?.status === 404
) {
return null;
}
throw error;
}
}
/**
* Update agent data
*/
async update<T = unknown>(
id: string,
options: UpdateAgentDataOptions<T>,
): Promise<TypedAgentData<T>> {
const response = await updateAgentDataApiV1BetaAgentDataItemIdPut({
throwOnError: true,
path: { item_id: id },
body: {
data: options.data as Record<string, unknown>,
},
client: this.client,
});
return this.transformResponse(response.data);
}
/**
* Delete agent data
*/
async delete(id: string): Promise<void> {
await deleteAgentDataApiV1BetaAgentDataItemIdDelete({
throwOnError: true,
path: { item_id: id },
client: this.client,
});
}
/**
* List agent data
*/
async list<T = unknown>(
options: ListAgentDataOptions,
): Promise<TypedAgentDataItems<T>> {
const response = await searchAgentDataApiV1BetaAgentDataSearchPost({
throwOnError: true,
body: {
agent_slug: options.agentSlug,
...(options.collection !== undefined && {
collection: options.collection,
}),
...(options.filter !== undefined && { filter: options.filter }),
...(options.orderBy !== undefined && { order_by: options.orderBy }),
...(options.pageSize !== undefined && { page_size: options.pageSize }),
...(options.pageToken !== undefined && {
page_token: options.pageToken,
}),
...(options.offset !== undefined && { offset: options.offset }),
},
client: this.client,
});
const result: TypedAgentDataItems<T> = {
items: response.data.items.map((item: AgentData) =>
this.transformResponse(item),
),
};
if (
response.data.total_size !== null &&
response.data.total_size !== undefined
) {
result.totalSize = response.data.total_size;
}
if (
response.data.next_page_token !== null &&
response.data.next_page_token !== undefined
) {
result.nextPageToken = response.data.next_page_token;
}
return result;
}
/**
* Extract data from agent with retry logic
*/
async extract<T = unknown>(
agentId: string,
input: unknown,
options?: ExtractOptions,
): Promise<ExtractedData<T>> {
const extractOptions = {
retries: options?.retryCount || 3,
onFailedAttempt: (error: {
attemptNumber: number;
retriesLeft: number;
}) => {
console.log(
`Extraction attempt ${error.attemptNumber} failed. ${error.retriesLeft} retries left.`,
);
},
minTimeout: options?.retryDelay || 1000,
maxTimeout: options?.timeout || 30000,
};
return pRetry(async () => {
// Note: The extract endpoint might not be in the generated client yet
// Using the native fetch API for this endpoint
const response = await fetch(
`${this.baseUrl}/api/v1/beta/agent-data/${agentId}/extract`,
{
method: "POST",
body: JSON.stringify({ input }),
headers: {
"Content-Type": "application/json",
...this.headers,
},
},
);
if (!response.ok) {
throw new Error(`Failed to extract data: ${response.statusText}`);
}
const extractedData = (await response.json()) as ExtractedData<T>;
// If status is still pending or in progress, poll for completion
if (
extractedData.status === "pending" ||
extractedData.status === "in_progress"
) {
return this.pollExtraction<T>(extractedData.id, options);
}
return extractedData;
}, extractOptions);
}
/**
* Poll for extraction completion
*/
private async pollExtraction<T = unknown>(
extractionId: string,
options?: ExtractOptions,
): Promise<ExtractedData<T>> {
const pollInterval = 2000; // 2 seconds
const maxAttempts = Math.floor((options?.timeout || 30000) / pollInterval);
for (let i = 0; i < maxAttempts; i++) {
await new Promise((resolve) => setTimeout(resolve, pollInterval));
const response = await fetch(
`${this.baseUrl}/api/v1/extractions/${extractionId}`,
{
headers: this.headers,
},
);
if (!response.ok) {
throw new Error(
`Failed to get extraction status: ${response.statusText}`,
);
}
const extractedData = (await response.json()) as ExtractedData<T>;
if (
extractedData.status === "completed" ||
extractedData.status === "failed"
) {
return extractedData;
}
}
throw new Error("Extraction timeout exceeded");
}
/**
* Transform API response to typed data
*/
private transformResponse<T = unknown>(data: AgentData): TypedAgentData<T> {
const result: TypedAgentData<T> = {
id: data.id!,
agentSlug: data.agent_slug,
data: data.data as T,
createdAt: new Date(data.created_at!),
updatedAt: new Date(data.updated_at!),
};
if (data.collection !== undefined) {
result.collection = data.collection;
}
return result;
}
}
/**
* Create a new AsyncAgentDataClient instance
*/
export function createAgentDataClient(options?: {
apiKey?: string;
baseUrl?: string;
}): AgentClient {
return new AgentClient(options);
}
-98
View File
@@ -1,98 +0,0 @@
/**
* Status types for agent data processing
*/
export enum StatusType {
PENDING = "pending",
IN_PROGRESS = "in_progress",
COMPLETED = "completed",
FAILED = "failed",
}
/**
* Filter operation for searching/filtering agent data
*/
export interface FilterOperation {
[key: string]: unknown;
}
/**
* Base extracted data interface
*/
export interface ExtractedData<T = unknown> {
id: string;
status: StatusType;
data?: T;
error?: string;
createdAt: Date;
updatedAt: Date;
}
/**
* TypedAgentData interface for typed agent data
*/
export interface TypedAgentData<T = unknown> {
id: string;
agentSlug: string;
collection?: string;
data: T;
createdAt: Date;
updatedAt: Date;
}
/**
* Collection of typed agent data items
*/
export interface TypedAgentDataItems<T = unknown> {
items: TypedAgentData<T>[];
totalSize?: number;
nextPageToken?: string;
}
/**
* Options for creating agent data
*/
export interface CreateAgentDataOptions<T = unknown> {
agentSlug: string;
collection?: string;
data: T;
}
/**
* Options for updating agent data
*/
export interface UpdateAgentDataOptions<T = unknown> {
data: T;
}
/**
* Sort options for listing
*/
export interface SortOptions {
field: string;
order: "asc" | "desc";
}
/**
* Options for listing agent data
*/
export interface ListAgentDataOptions {
agentSlug: string;
collection?: string;
filter?: Record<string, FilterOperation>;
orderBy?: string;
pageSize?: number;
pageToken?: string;
offset?: number;
}
/**
* Options for extraction
*/
export interface ExtractOptions {
timeout?: number;
retryCount?: number;
retryDelay?: number;
}
export type ExtractedT<T> = T;
export type AgentDataT<T> = T;
+314
View File
@@ -0,0 +1,314 @@
import { createClient, createConfig } from "@hey-api/client-fetch";
import { getEnv } from "@llamaindex/env";
import {
aggregateAgentDataApiV1BetaAgentDataAggregatePost,
createAgentDataApiV1BetaAgentDataPost,
deleteAgentDataApiV1BetaAgentDataItemIdDelete,
getAgentDataApiV1BetaAgentDataItemIdGet,
searchAgentDataApiV1BetaAgentDataSearchPost,
updateAgentDataApiV1BetaAgentDataItemIdPut,
type AgentData,
type AggregateGroup,
} from "../../client";
import type {
AggregateAgentDataOptions,
SearchAgentDataOptions,
TypedAgentData,
TypedAgentDataItems,
TypedAggregateGroup,
TypedAggregateGroupItems,
} from "./types";
/**
* Async client for agent data operations
*/
export class AgentClient<T = unknown> {
private client: ReturnType<typeof createClient>;
private baseUrl: string;
private headers: Record<string, string>;
private collection: string;
private agentUrlId: string;
constructor({
apiKey = getEnv("LLAMA_CLOUD_API_KEY"),
baseUrl = "https://api.cloud.llamaindex.ai/",
collection = "default",
agentUrlId = "default",
}: {
apiKey?: string;
baseUrl?: string;
collection?: string;
agentUrlId?: string;
}) {
this.baseUrl = baseUrl;
this.headers = {
"X-SDK-Name": "llamaindex-ts",
...(apiKey && { Authorization: `Bearer ${apiKey}` }),
};
this.client = createClient(
createConfig({
baseUrl: this.baseUrl,
headers: this.headers,
}),
);
this.collection = collection;
this.agentUrlId = agentUrlId;
}
/**
* Create new agent data
*/
async createItem(data: T): Promise<TypedAgentData<T>> {
const response = await createAgentDataApiV1BetaAgentDataPost({
throwOnError: true,
body: {
agent_slug: this.agentUrlId,
collection: this.collection,
data: data as Record<string, unknown>,
},
client: this.client,
});
return this.transformResponse(response.data);
}
/**
* Get agent data by ID
*/
async getItem(id: string): Promise<TypedAgentData<T> | null> {
try {
const response = await getAgentDataApiV1BetaAgentDataItemIdGet({
throwOnError: true,
path: { item_id: id },
client: this.client,
});
return this.transformResponse(response.data);
} catch (error) {
if (
error instanceof Error &&
"response" in error &&
(error as { response?: { status?: number } }).response?.status === 404
) {
return null;
}
throw error;
}
}
/**
* Update agent data
*/
async updateItem(id: string, data: T): Promise<TypedAgentData<T>> {
const response = await updateAgentDataApiV1BetaAgentDataItemIdPut({
throwOnError: true,
path: { item_id: id },
body: {
data: data as Record<string, unknown>,
},
client: this.client,
});
return this.transformResponse(response.data);
}
/**
* Delete agent data
*/
async deleteItem(id: string): Promise<void> {
await deleteAgentDataApiV1BetaAgentDataItemIdDelete({
throwOnError: true,
path: { item_id: id },
client: this.client,
});
}
/**
* List agent data
*/
async search(
options: SearchAgentDataOptions,
): Promise<TypedAgentDataItems<T>> {
const response = await searchAgentDataApiV1BetaAgentDataSearchPost({
throwOnError: true,
body: {
agent_slug: this.agentUrlId,
...(this.collection !== undefined && {
collection: this.collection,
}),
...(options.filter !== undefined && { filter: options.filter }),
...(options.orderBy !== undefined && { order_by: options.orderBy }),
...(options.pageSize !== undefined && { page_size: options.pageSize }),
...(options.offset !== undefined && { offset: options.offset }),
...(options.includeTotal !== undefined && {
include_total: options.includeTotal,
}),
},
client: this.client,
});
const result: TypedAgentDataItems<T> = {
items: response.data.items.map((item: AgentData) =>
this.transformResponse(item),
),
};
if (
response.data.total_size !== null &&
response.data.total_size !== undefined
) {
result.totalSize = response.data.total_size;
}
if (
response.data.next_page_token !== null &&
response.data.next_page_token !== undefined
) {
result.nextPageToken = response.data.next_page_token;
}
return result;
}
/**
* Aggregate agent data into groups
*/
async aggregate(
options: AggregateAgentDataOptions,
): Promise<TypedAggregateGroupItems<T>> {
const response = await aggregateAgentDataApiV1BetaAgentDataAggregatePost({
throwOnError: true,
body: {
agent_slug: this.agentUrlId,
...(this.collection !== undefined && {
collection: this.collection,
}),
...(options.filter !== undefined && { filter: options.filter }),
...(options.groupBy !== undefined && { group_by: options.groupBy }),
...(options.count !== undefined && { count: options.count }),
...(options.first !== undefined && { first: options.first }),
...(options.orderBy !== undefined && { order_by: options.orderBy }),
...(options.offset !== undefined && { offset: options.offset }),
...(options.pageSize !== undefined && { page_size: options.pageSize }),
},
client: this.client,
});
const result: TypedAggregateGroupItems<T> = {
items: response.data.items.map((item) =>
this.transformAggregateResponse(item),
),
};
if (
response.data.total_size !== null &&
response.data.total_size !== undefined
) {
result.totalSize = response.data.total_size;
}
if (
response.data.next_page_token !== null &&
response.data.next_page_token !== undefined
) {
result.nextPageToken = response.data.next_page_token;
}
return result;
}
/**
* Transform API response to typed data
*/
private transformResponse(data: AgentData): TypedAgentData<T> {
const result: TypedAgentData<T> = {
id: data.id!,
agentUrlId: data.agent_slug,
data: data.data as T,
createdAt: new Date(data.created_at!),
updatedAt: new Date(data.updated_at!),
};
if (data.collection !== undefined) {
result.collection = data.collection;
}
return result;
}
/**
* Transform API aggregate response to typed data
*/
private transformAggregateResponse(
data: AggregateGroup,
): TypedAggregateGroup<T> {
const result: TypedAggregateGroup<T> = {
groupKey: data.group_key,
};
if (data.count !== null && data.count !== undefined) {
result.count = data.count;
}
if (data.first_item !== null && data.first_item !== undefined) {
result.firstItem = data.first_item as T;
}
return result;
}
}
export interface AgentDataClientOptions<T = unknown> {
/** API key for the client */
apiKey?: string;
/** 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 */
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;
/** Collection name for the client, defaults to "default" */
collection?: string;
}
/**
* Create a new AsyncAgentDataClient instance
* @param options - The options for the client
* @returns A new AgentClient instance
*/
export function createAgentDataClient<T = unknown>({
apiKey,
baseUrl,
windowUrl,
agentUrlId,
collection = "default",
}: {
apiKey?: string;
baseUrl?: string;
windowUrl?: string;
agentUrlId?: string;
collection?: string;
} = {}): AgentClient<T> {
if (windowUrl && !agentUrlId) {
try {
const path = new URL(windowUrl).pathname;
// /deployments/<agent-url-id>/ui/ -> ["", "deployments", "<agent-url-id>", "ui"]
agentUrlId = path.split("/")[2];
} catch (error) {
console.warn(
"Failed to infer agent url id from window url, falling back to default",
error,
);
}
}
return new AgentClient({
...(apiKey && { apiKey }),
...(baseUrl && { baseUrl }),
...(agentUrlId && { agentUrlId }),
collection,
});
}
@@ -1,18 +1,16 @@
export { AgentClient, createAgentDataClient } from "./client";
export type {
AgentDataT,
CreateAgentDataOptions,
ExtractOptions,
AggregateAgentDataOptions,
ComparisonOperator,
ExtractedData,
ExtractedT,
FilterOperation,
ListAgentDataOptions,
SortOptions,
SearchAgentDataOptions,
StatusType,
TypedAgentData,
TypedAgentDataItems,
UpdateAgentDataOptions,
TypedAggregateGroup,
TypedAggregateGroupItems,
} from "./types";
export { StatusType as StatusTypeEnum } from "./types";
+138
View File
@@ -0,0 +1,138 @@
import type { FilterOperation as RawFilterOperation } from "../../client/types.gen";
/**
* Status types for agent data processing
*/
export const StatusType = {
ERROR: "error",
ACCEPTED: "accepted",
REJECTED: "rejected",
PENDING_REVIEW: "pending_review",
} as const;
export type StatusType = (typeof StatusType)[keyof typeof StatusType];
export const ComparisonOperator = {
GT: "gt",
GTE: "gte",
LT: "lt",
LTE: "lte",
EQ: "eq",
INCLUDES: "includes",
} as const;
export type ComparisonOperator =
(typeof ComparisonOperator)[keyof typeof ComparisonOperator];
/**
* Filter operation for searching/filtering agent data
*/
export type FilterOperation = RawFilterOperation;
/**
* Base extracted data interface
*/
export interface ExtractedData<T = unknown> {
/** The original data that was extracted from the document. For tracking changes. Should not be updated. */
original_data: T;
/** The latest state of the data. Will differ if data has been updated. */
data?: T;
/** The status of the extracted data. Prefer to use the StatusType values, but any string is allowed. */
status: StatusType | string;
/** Confidence scores, if any, for each primitive field in the original_data data. */
confidence?: Record<string, unknown>;
/** The ID of the file that was used to extract the data. */
file_id?: string;
/** The name of the file that was used to extract the data. */
file_name?: string;
/** The hash of the file that was used to extract the data. */
file_hash?: string;
/** Additional metadata about the extracted data, such as errors, tokens, etc. */
metadata?: Record<string, unknown>;
}
/**
* TypedAgentData interface for typed agent data
*/
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 collection of the agent data. */
collection?: string;
/** The data of the agent data. Usually an ExtractedData&lt;SomeOtherType&gt; */
data: T;
/** The date and time the data was created. */
createdAt: Date;
/** The date and time the data was last updated. */
updatedAt: Date;
}
/**
* Paginated response of typed agent data items
*/
export interface TypedAgentDataItems<T = unknown> {
items: TypedAgentData<T>[];
totalSize?: number;
nextPageToken?: string;
}
/**
* Options for listing agent data
*/
export interface SearchAgentDataOptions {
/** Filter options for the list. */
filter?: Record<string, FilterOperation>;
/** Order by options for the list. */
orderBy?: string;
/** Page size for the list. */
pageSize?: number;
/** Offset for the list. */
offset?: number;
/**
* Whether to include the total number of items in the response.
* Should use only for first request to build total pagination, and not subsequent requests.
*/
includeTotal?: boolean;
}
/**
* Options for aggregating agent data
*/
export interface AggregateAgentDataOptions {
/** Filter options for the aggregation. */
filter?: Record<string, FilterOperation>;
/** Fields to group by. */
groupBy?: string[];
/** Whether to count the number of items in each group. */
count?: boolean;
/** Whether to return the first item in each group. */
first?: boolean;
/** Order by options for the aggregation. */
orderBy?: string;
/** Offset for the aggregation. */
offset?: number;
/** Page size for the aggregation. */
pageSize?: number;
}
/**
* Single aggregation group result
*/
export interface TypedAggregateGroup<T = unknown> {
/** The group key values */
groupKey: Record<string, unknown>;
/** Count of items in the group */
count?: number;
/** First item in the group */
firstItem?: T;
}
/**
* Paginated response of aggregated agent data
*/
export interface TypedAggregateGroupItems<T = unknown> {
items: TypedAggregateGroup<T>[];
totalSize?: number;
nextPageToken?: string;
}