vectara-agentic 0.2.23__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vectara-agentic might be problematic. Click here for more details.

@@ -6,8 +6,16 @@ import inspect
6
6
  import re
7
7
 
8
8
  from typing import (
9
- Callable, List, Dict, Any, Optional, Union, Type, Tuple,
10
- get_origin, get_args
9
+ Callable,
10
+ List,
11
+ Dict,
12
+ Any,
13
+ Optional,
14
+ Union,
15
+ Type,
16
+ Tuple,
17
+ get_origin,
18
+ get_args,
11
19
  )
12
20
  from pydantic import BaseModel, create_model
13
21
  from pydantic_core import PydanticUndefined
@@ -83,7 +91,7 @@ class VectaraTool(FunctionTool):
83
91
  tool_metadata,
84
92
  callback,
85
93
  async_callback,
86
- partial_params
94
+ partial_params,
87
95
  )
88
96
  vectara_tool = cls(
89
97
  tool_type=tool_type,
@@ -119,7 +127,8 @@ class VectaraTool(FunctionTool):
119
127
  self, *args: Any, ctx: Optional[Context] = None, **kwargs: Any
120
128
  ) -> ToolOutput:
121
129
  try:
122
- return super().call(*args, ctx=ctx, **kwargs)
130
+ result = super().call(*args, ctx=ctx, **kwargs)
131
+ return self._format_tool_output(result)
123
132
  except TypeError as e:
124
133
  sig = inspect.signature(self.metadata.fn_schema)
125
134
  valid_parameters = list(sig.parameters.keys())
@@ -148,7 +157,8 @@ class VectaraTool(FunctionTool):
148
157
  self, *args: Any, ctx: Optional[Context] = None, **kwargs: Any
149
158
  ) -> ToolOutput:
150
159
  try:
151
- return await super().acall(*args, ctx=ctx, **kwargs)
160
+ result = await super().acall(*args, ctx=ctx, **kwargs)
161
+ return self._format_tool_output(result)
152
162
  except TypeError as e:
153
163
  sig = inspect.signature(self.metadata.fn_schema)
154
164
  valid_parameters = list(sig.parameters.keys())
@@ -166,6 +176,7 @@ class VectaraTool(FunctionTool):
166
176
  return err_output
167
177
  except Exception as e:
168
178
  import traceback
179
+
169
180
  err_output = ToolOutput(
170
181
  tool_name=self.metadata.name,
171
182
  content=f"Tool {self.metadata.name} Malfunction: {str(e)}, traceback: {traceback.format_exc()}",
@@ -174,10 +185,39 @@ class VectaraTool(FunctionTool):
174
185
  )
175
186
  return err_output
176
187
 
188
+ def _format_tool_output(self, result: ToolOutput) -> ToolOutput:
189
+ """Format tool output to use human-readable representation if available."""
190
+ if hasattr(result, "content") and _is_human_readable_output(result.content):
191
+ try:
192
+ # Use human-readable format for content, keep raw output
193
+ human_readable_content = result.content.to_human_readable()
194
+ raw_output = result.content.get_raw_output()
195
+ return ToolOutput(
196
+ tool_name=result.tool_name,
197
+ content=human_readable_content,
198
+ raw_input=result.raw_input,
199
+ raw_output=raw_output,
200
+ )
201
+ except Exception as e:
202
+ # If formatting fails, fall back to original content with error info
203
+ import logging
204
+
205
+ logging.warning(
206
+ f"Failed to format tool output for {result.tool_name}: {e}"
207
+ )
208
+ return ToolOutput(
209
+ tool_name=result.tool_name,
210
+ content=f"[Formatting Error] {str(result.content)}",
211
+ raw_input=result.raw_input,
212
+ raw_output={"error": str(e), "original_content": result.content},
213
+ )
214
+ return result
215
+
177
216
 
178
217
  class EmptyBaseModel(BaseModel):
179
218
  """empty base model"""
180
219
 
220
+
181
221
  def _clean_type_repr(type_repr: str) -> str:
182
222
  """Cleans the string representation of a type."""
183
223
  # Replace <class 'somename'> with somename
@@ -188,6 +228,7 @@ def _clean_type_repr(type_repr: str) -> str:
188
228
  type_repr = type_repr.replace("typing.", "")
189
229
  return type_repr
190
230
 
231
+
191
232
  def _format_type(annotation) -> str:
192
233
  """
193
234
  Turn things like Union[int, str, NoneType] into 'int | str | None',
@@ -209,6 +250,7 @@ def _format_type(annotation) -> str:
209
250
  type_repr = _clean_type_repr(type_repr)
210
251
  return type_repr.replace("NoneType", "None")
211
252
 
253
+
212
254
  def _make_docstring(
213
255
  function: Callable[..., ToolOutput],
214
256
  tool_name: str,
@@ -267,11 +309,15 @@ def _make_docstring(
267
309
  ty_info = schema_prop["type"]
268
310
  if isinstance(ty_info, str):
269
311
  ty_str = _clean_type_repr(ty_info)
270
- elif isinstance(ty_info, list): # Handle JSON schema array type e.g., ["integer", "string"]
312
+ elif isinstance(
313
+ ty_info, list
314
+ ): # Handle JSON schema array type e.g., ["integer", "string"]
271
315
  ty_str = " | ".join([_clean_type_repr(t) for t in ty_info])
272
316
 
273
317
  # inline default if present
274
- default_txt = f", default={default!r}" if default is not PydanticUndefined else ""
318
+ default_txt = (
319
+ f", default={default!r}" if default is not PydanticUndefined else ""
320
+ )
275
321
 
276
322
  # inline examples if any
277
323
  if examples:
@@ -288,8 +334,8 @@ def _make_docstring(
288
334
  doc_lines.append(f" dict[str, Any]: {return_desc}")
289
335
 
290
336
  initial_docstring = "\n".join(doc_lines)
291
- collapsed_spaces = re.sub(r' {2,}', ' ', initial_docstring)
292
- final_docstring = re.sub(r'\n{2,}', '\n', collapsed_spaces).strip()
337
+ collapsed_spaces = re.sub(r" {2,}", " ", initial_docstring)
338
+ final_docstring = re.sub(r"\n{2,}", "\n", collapsed_spaces).strip()
293
339
  return final_docstring
294
340
 
295
341
 
@@ -317,13 +363,17 @@ def create_tool_from_dynamic_function(
317
363
  if tool_args_schema is None:
318
364
  tool_args_schema = EmptyBaseModel
319
365
 
320
- if not isinstance(tool_args_schema, type) or not issubclass(tool_args_schema, BaseModel):
366
+ if not isinstance(tool_args_schema, type) or not issubclass(
367
+ tool_args_schema, BaseModel
368
+ ):
321
369
  raise TypeError("tool_args_schema must be a Pydantic BaseModel subclass")
322
370
 
323
371
  fields: Dict[str, Any] = {}
324
372
  base_params = []
325
373
  for field_name, field_info in base_params_model.model_fields.items():
326
- default = Ellipsis if field_info.default is PydanticUndefined else field_info.default
374
+ default = (
375
+ Ellipsis if field_info.default is PydanticUndefined else field_info.default
376
+ )
327
377
  param = inspect.Parameter(
328
378
  field_name,
329
379
  inspect.Parameter.POSITIONAL_OR_KEYWORD,
@@ -338,7 +388,9 @@ def create_tool_from_dynamic_function(
338
388
  if field_name in fields:
339
389
  continue
340
390
 
341
- default = Ellipsis if field_info.default is PydanticUndefined else field_info.default
391
+ default = (
392
+ Ellipsis if field_info.default is PydanticUndefined else field_info.default
393
+ )
342
394
  param = inspect.Parameter(
343
395
  field_name,
344
396
  inspect.Parameter.POSITIONAL_OR_KEYWORD,
@@ -362,9 +414,7 @@ def create_tool_from_dynamic_function(
362
414
  function.__name__ = re.sub(r"[^A-Za-z0-9_]", "_", tool_name)
363
415
 
364
416
  function.__doc__ = _make_docstring(
365
- function,
366
- tool_name, tool_description, fn_schema,
367
- all_params, compact_docstring
417
+ function, tool_name, tool_description, fn_schema, all_params, compact_docstring
368
418
  )
369
419
  tool = VectaraTool.from_defaults(
370
420
  fn=function,
@@ -526,3 +576,115 @@ def build_filter_string(
526
576
  if fixed_filter and joined:
527
577
  return f"({fixed_filter}) AND ({joined})"
528
578
  return fixed_filter or joined
579
+
580
+
581
+ def _is_human_readable_output(obj: Any) -> bool:
582
+ """Check if an object implements the HumanReadableOutput protocol."""
583
+ return (
584
+ hasattr(obj, "to_human_readable")
585
+ and hasattr(obj, "get_raw_output")
586
+ and callable(getattr(obj, "to_human_readable", None))
587
+ and callable(getattr(obj, "get_raw_output", None))
588
+ )
589
+
590
+
591
+ def create_human_readable_output(
592
+ raw_output: Any, formatter: Optional[Callable[[Any], str]] = None
593
+ ) -> "HumanReadableToolOutput":
594
+ """Create a HumanReadableToolOutput wrapper for tool outputs."""
595
+ return HumanReadableToolOutput(raw_output, formatter)
596
+
597
+
598
+ def format_as_table(data: List[Dict[str, Any]], max_width: int = 80) -> str:
599
+ """Format list of dictionaries as a table."""
600
+ if not data:
601
+ return "No data to display"
602
+
603
+ # Get all unique keys
604
+ all_keys = set()
605
+ for item in data:
606
+ all_keys.update(item.keys())
607
+
608
+ headers = list(all_keys)
609
+
610
+ # Calculate column widths
611
+ col_widths = {}
612
+ for header in headers:
613
+ col_widths[header] = max(
614
+ len(header), max(len(str(item.get(header, ""))) for item in data)
615
+ )
616
+ # Limit column width
617
+ col_widths[header] = min(col_widths[header], max_width // len(headers))
618
+
619
+ # Create table
620
+ lines = []
621
+
622
+ # Header row
623
+ header_row = " | ".join(header.ljust(col_widths[header]) for header in headers)
624
+ lines.append(header_row)
625
+ lines.append("-" * len(header_row))
626
+
627
+ # Data rows
628
+ for item in data:
629
+ row = " | ".join(
630
+ str(item.get(header, "")).ljust(col_widths[header])[: col_widths[header]]
631
+ for header in headers
632
+ )
633
+ lines.append(row)
634
+
635
+ return "\n".join(lines)
636
+
637
+
638
+ def format_as_json(data: Any, indent: int = 2) -> str:
639
+ """Format data as pretty-printed JSON."""
640
+ import json
641
+
642
+ try:
643
+ return json.dumps(data, indent=indent, ensure_ascii=False)
644
+ except (TypeError, ValueError):
645
+ return str(data)
646
+
647
+
648
+ def format_as_markdown_list(items: List[Any], numbered: bool = False) -> str:
649
+ """Format items as markdown list."""
650
+ if not items:
651
+ return "No items to display"
652
+
653
+ if numbered:
654
+ return "\n".join(f"{i+1}. {item}" for i, item in enumerate(items))
655
+ else:
656
+ return "\n".join(f"- {item}" for item in items)
657
+
658
+
659
+ class HumanReadableToolOutput:
660
+ """Wrapper class that implements HumanReadableOutput protocol."""
661
+
662
+ def __init__(
663
+ self, raw_output: Any, formatter: Optional[Callable[[Any], str]] = None
664
+ ):
665
+ self._raw_output = raw_output
666
+ self._formatter = formatter or str
667
+
668
+ def to_human_readable(self) -> str:
669
+ """Convert the output to a human-readable format."""
670
+ try:
671
+ return self._formatter(self._raw_output)
672
+ except Exception as e:
673
+ import logging
674
+
675
+ logging.warning(f"Failed to format output with custom formatter: {e}")
676
+ # Fallback to string representation
677
+ try:
678
+ return str(self._raw_output)
679
+ except Exception:
680
+ return f"[Error formatting output: {e}]"
681
+
682
+ def get_raw_output(self) -> Any:
683
+ """Get the raw output data."""
684
+ return self._raw_output
685
+
686
+ def __str__(self) -> str:
687
+ return self.to_human_readable()
688
+
689
+ def __repr__(self) -> str:
690
+ return f"HumanReadableToolOutput({self._raw_output!r})"
vectara_agentic/tools.py CHANGED
@@ -14,7 +14,6 @@ from pydantic import BaseModel, Field
14
14
  from llama_index.core.tools import FunctionTool
15
15
  from llama_index.indices.managed.vectara import VectaraIndex
16
16
  from llama_index.core.utilities.sql_wrapper import SQLDatabase
17
- from llama_index.core.tools.types import ToolOutput
18
17
 
19
18
  from .types import ToolType
20
19
  from .tools_catalog import ToolsCatalog, get_bad_topics
@@ -25,6 +24,7 @@ from .tool_utils import (
25
24
  create_tool_from_dynamic_function,
26
25
  build_filter_string,
27
26
  VectaraTool,
27
+ create_human_readable_output,
28
28
  )
29
29
 
30
30
  LI_packages = {
@@ -170,7 +170,7 @@ class VectaraToolFactory:
170
170
  )
171
171
 
172
172
  # Dynamically generate the search function
173
- def search_function(*args: Any, **kwargs: Any) -> ToolOutput:
173
+ def search_function(*args: Any, **kwargs: Any) -> list[dict]:
174
174
  """
175
175
  Dynamically generated function for semantic search Vectara.
176
176
  """
@@ -192,12 +192,11 @@ class VectaraToolFactory:
192
192
  kwargs, tool_args_type, fixed_filter
193
193
  )
194
194
  except ValueError as e:
195
- return ToolOutput(
196
- tool_name=search_function.__name__,
197
- content=str(e),
198
- raw_input={"args": args, "kwargs": kwargs},
199
- raw_output={"response": str(e)},
195
+ msg = (
196
+ f"Building filter string failed in search tool due to invalid input or configuration ({e}). "
197
+ "Please verify the input arguments and ensure they meet the expected format or conditions."
200
198
  )
199
+ return [{"text": msg, "metadata": {"args": args, "kwargs": kwargs}}]
201
200
 
202
201
  vectara_retriever = vectara.as_retriever(
203
202
  summary_enabled=False,
@@ -228,20 +227,19 @@ class VectaraToolFactory:
228
227
 
229
228
  if len(response) == 0:
230
229
  msg = "Vectara Tool failed to retrieve any results for the query."
231
- return ToolOutput(
232
- tool_name=search_function.__name__,
233
- content=msg,
234
- raw_input={"args": args, "kwargs": kwargs},
235
- raw_output={"response": msg},
236
- )
230
+ return [{"text": msg, "metadata": {"args": args, "kwargs": kwargs}}]
237
231
  unique_ids = set()
238
232
  docs = []
233
+ doc_matches = {}
239
234
  for doc in response:
240
235
  if doc.id_ in unique_ids:
236
+ doc_matches[doc.id_].append(doc.node.get_content())
241
237
  continue
242
238
  unique_ids.add(doc.id_)
239
+ doc_matches[doc.id_] = [doc.node.get_content()]
243
240
  docs.append((doc.id_, doc.metadata))
244
- tool_output = "Matching documents:\n"
241
+
242
+ res = []
245
243
  if summarize:
246
244
  summaries_dict = asyncio.run(
247
245
  summarize_documents(
@@ -251,22 +249,50 @@ class VectaraToolFactory:
251
249
  doc_ids=list(unique_ids),
252
250
  )
253
251
  )
254
- for doc_id, metadata in docs:
255
- summary = summaries_dict.get(doc_id, "")
256
- tool_output += f"document_id: '{doc_id}'\nmetadata: '{metadata}'\nsummary: '{summary}'\n\n"
257
252
  else:
258
- for doc_id, metadata in docs:
259
- tool_output += (
260
- f"document_id: '{doc_id}'\nmetadata: '{metadata}'\n\n"
253
+ summaries_dict = {}
254
+
255
+ for doc_id, metadata in docs:
256
+ res.append(
257
+ {
258
+ "text": summaries_dict.get(doc_id, "") if summarize else "",
259
+ "metadata": {
260
+ "document_id": doc_id,
261
+ "metadata": metadata,
262
+ "matching_text": doc_matches[doc_id],
263
+ },
264
+ }
265
+ )
266
+
267
+ # Create human-readable output using sequential format
268
+ def format_search_results(results):
269
+ if not results:
270
+ return "No search results found"
271
+
272
+ # Create a sequential view for human reading
273
+ formatted_results = []
274
+ for i, result in enumerate(results, 1):
275
+ result_str = f"**Result #{i}**\n"
276
+ result_str += f"Document ID: {result['metadata']['document_id']}\n"
277
+ result_str += (
278
+ f"Matches: {len(result['metadata']['matching_text'])}\n"
261
279
  )
262
280
 
263
- out = ToolOutput(
264
- tool_name=search_function.__name__,
265
- content=tool_output,
266
- raw_input={"args": args, "kwargs": kwargs},
267
- raw_output=response,
268
- )
269
- return out
281
+ if summarize and result["text"]:
282
+ result_str += f"Summary: {result['text']}\n"
283
+
284
+ # Add sample matching text if available
285
+ if result["metadata"]["matching_text"]:
286
+ sample_matches = result["metadata"]["matching_text"][
287
+ :2
288
+ ] # Show first 2 matches
289
+ result_str += f"Sample matches: {', '.join(sample_matches)}\n"
290
+
291
+ formatted_results.append(result_str)
292
+
293
+ return "\n".join(formatted_results)
294
+
295
+ return create_human_readable_output(res, format_search_results)
270
296
 
271
297
  class SearchToolBaseParams(BaseModel):
272
298
  """Model for the base parameters of the search tool."""
@@ -346,6 +372,7 @@ class VectaraToolFactory:
346
372
  frequency_penalty: Optional[float] = None,
347
373
  presence_penalty: Optional[float] = None,
348
374
  include_citations: bool = True,
375
+ citation_pattern: str = "{doc.url}",
349
376
  save_history: bool = False,
350
377
  fcs_threshold: float = 0.0,
351
378
  return_direct: bool = False,
@@ -399,6 +426,9 @@ class VectaraToolFactory:
399
426
  higher values increasing the diversity of topics.
400
427
  include_citations (bool, optional): Whether to include citations in the response.
401
428
  If True, uses markdown vectara citations that requires the Vectara scale plan.
429
+ citation_pattern (str, optional): The pattern for the citations in the response.
430
+ Default is "{doc.url}" which uses the document URL.
431
+ If include_citations is False, this parameter is ignored.
402
432
  save_history (bool, optional): Whether to save the query in history.
403
433
  fcs_threshold (float, optional): A threshold for factual consistency.
404
434
  If set above 0, the tool notifies the calling agent that it "cannot respond" if FCS is too low.
@@ -420,7 +450,7 @@ class VectaraToolFactory:
420
450
  )
421
451
 
422
452
  # Dynamically generate the RAG function
423
- def rag_function(*args: Any, **kwargs: Any) -> ToolOutput:
453
+ def rag_function(*args: Any, **kwargs: Any) -> dict:
424
454
  """
425
455
  Dynamically generated function for RAG query with Vectara.
426
456
  """
@@ -436,12 +466,12 @@ class VectaraToolFactory:
436
466
  kwargs, tool_args_type, fixed_filter
437
467
  )
438
468
  except ValueError as e:
439
- return ToolOutput(
440
- tool_name=rag_function.__name__,
441
- content=str(e),
442
- raw_input={"args": args, "kwargs": kwargs},
443
- raw_output={"response": str(e)},
469
+ msg = (
470
+ f"Building filter string failed in rag tool. "
471
+ f"Reason: {e}. Ensure that the input arguments match the expected "
472
+ f"format and include all required fields. "
444
473
  )
474
+ return {"text": msg, "metadata": {"args": args, "kwargs": kwargs}}
445
475
 
446
476
  vectara_query_engine = vectara.as_query_engine(
447
477
  summary_enabled=True,
@@ -475,7 +505,7 @@ class VectaraToolFactory:
475
505
  frequency_penalty=frequency_penalty,
476
506
  presence_penalty=presence_penalty,
477
507
  citations_style="markdown" if include_citations else None,
478
- citations_url_pattern="{doc.url}" if include_citations else None,
508
+ citations_url_pattern=citation_pattern if include_citations else None,
479
509
  save_history=save_history,
480
510
  x_source_str="vectara-agentic",
481
511
  verbose=verbose,
@@ -487,73 +517,59 @@ class VectaraToolFactory:
487
517
  "Tool failed to generate a response since no matches were found. "
488
518
  "Please check the arguments and try again."
489
519
  )
490
- return ToolOutput(
491
- tool_name=rag_function.__name__,
492
- content=msg,
493
- raw_input={"args": args, "kwargs": kwargs},
494
- raw_output={"response": msg},
495
- )
520
+ return {"text": msg, "metadata": {"args": args, "kwargs": kwargs}}
496
521
  if str(response) == "None":
497
522
  msg = "Tool failed to generate a response."
498
- return ToolOutput(
499
- tool_name=rag_function.__name__,
500
- content=msg,
501
- raw_input={"args": args, "kwargs": kwargs},
502
- raw_output={"response": msg},
503
- )
523
+ return {"text": msg, "metadata": {"args": args, "kwargs": kwargs}}
504
524
 
505
525
  # Extract citation metadata
506
526
  pattern = r"\[(\d+)\]"
507
527
  matches = re.findall(pattern, response.response)
508
528
  citation_numbers = sorted(set(int(match) for match in matches))
509
- citation_metadata = ""
529
+ citation_metadata = {}
510
530
  keys_to_ignore = ["lang", "offset", "len"]
511
531
  for citation_number in citation_numbers:
512
- metadata = response.source_nodes[citation_number - 1].metadata
513
- citation_metadata += (
514
- f"[{citation_number}]: "
515
- + "; ".join(
516
- [
517
- f"{k}='{v}'"
518
- for k, v in metadata.items()
519
- if k not in keys_to_ignore
520
- ]
521
- )
522
- + ".\n"
523
- )
532
+ metadata = {
533
+ k: v
534
+ for k, v in response.source_nodes[
535
+ citation_number - 1
536
+ ].metadata.items()
537
+ if k not in keys_to_ignore
538
+ }
539
+ citation_metadata[str(citation_number)] = metadata
524
540
  fcs = 0.0
525
541
  fcs_str = response.metadata["fcs"] if "fcs" in response.metadata else "0.0"
526
542
  if fcs_str and is_float(fcs_str):
527
543
  fcs = float(fcs_str)
528
544
  if fcs < fcs_threshold:
529
545
  msg = f"Could not answer the query due to suspected hallucination (fcs={fcs})."
530
- return ToolOutput(
531
- tool_name=rag_function.__name__,
532
- content=msg,
533
- raw_input={"args": args, "kwargs": kwargs},
534
- raw_output={"response": msg},
535
- )
536
- res = {
537
- "response": response.response,
538
- "references_metadata": citation_metadata,
539
- "fcs_score": fcs,
540
- }
541
- if len(citation_metadata) > 0:
542
- tool_output = f"""
543
- Response: '''{res['response']}'''
544
- fcs_score: {res['fcs_score']:.4f}
545
- References:
546
- {res['references_metadata']}
547
- """
548
- else:
549
- tool_output = f"Response: '''{res['response']}'''"
550
- out = ToolOutput(
551
- tool_name=rag_function.__name__,
552
- content=tool_output,
553
- raw_input={"args": args, "kwargs": kwargs},
554
- raw_output=res,
555
- )
556
- return out
546
+ return {
547
+ "text": msg,
548
+ "metadata": {"args": args, "kwargs": kwargs, "fcs": fcs},
549
+ }
550
+ if fcs:
551
+ citation_metadata["fcs"] = fcs
552
+
553
+ res = {"text": response.response, "metadata": citation_metadata}
554
+
555
+ # Create human-readable output with citation formatting
556
+ def format_rag_response(result):
557
+ text = result["text"]
558
+ metadata = result["metadata"]
559
+
560
+ # Format citations if present
561
+ citation_info = []
562
+ for key, value in metadata.items():
563
+ if key.isdigit():
564
+ url = value.get("document", {}).get("url", None)
565
+ if url:
566
+ citation_info.append(f"[{key}]: {url}")
567
+ if citation_info:
568
+ text += "\n\nCitations:\n" + "\n".join(citation_info)
569
+
570
+ return text
571
+
572
+ return create_human_readable_output(res, format_rag_response)
557
573
 
558
574
  class RagToolBaseParams(BaseModel):
559
575
  """Model for the base parameters of the RAG tool."""
vectara_agentic/types.py CHANGED
@@ -1,11 +1,17 @@
1
1
  """
2
2
  This module contains the types used in the Vectara Agentic.
3
3
  """
4
+
4
5
  from enum import Enum
6
+ from typing import Protocol, Any
5
7
 
8
+ from llama_index.core.schema import Document as LI_Document
6
9
  from llama_index.core.tools.types import ToolOutput as LI_ToolOutput
7
10
  from llama_index.core.chat_engine.types import AgentChatResponse as LI_AgentChatResponse
8
- from llama_index.core.chat_engine.types import StreamingAgentChatResponse as LI_StreamingAgentChatResponse
11
+ from llama_index.core.chat_engine.types import (
12
+ StreamingAgentChatResponse as LI_StreamingAgentChatResponse,
13
+ )
14
+
9
15
 
10
16
  class AgentType(Enum):
11
17
  """Enumeration for different types of agents."""
@@ -16,6 +22,7 @@ class AgentType(Enum):
16
22
  LLMCOMPILER = "LLMCOMPILER"
17
23
  LATS = "LATS"
18
24
 
25
+
19
26
  class ObserverType(Enum):
20
27
  """Enumeration for different types of observability integrations."""
21
28
 
@@ -55,16 +62,30 @@ class LLMRole(Enum):
55
62
 
56
63
  class ToolType(Enum):
57
64
  """Enumeration for different types of tools."""
65
+
58
66
  QUERY = "query"
59
67
  ACTION = "action"
60
68
 
69
+
61
70
  class AgentConfigType(Enum):
62
71
  """Enumeration for different types of agent configurations."""
72
+
63
73
  DEFAULT = "default"
64
74
  FALLBACK = "fallback"
65
75
 
66
76
 
77
+ class HumanReadableOutput(Protocol):
78
+ """Protocol for tool outputs that can provide human-readable representations."""
79
+
80
+ def to_human_readable(self) -> str:
81
+ """Convert the output to a human-readable format."""
82
+
83
+ def get_raw_output(self) -> Any:
84
+ """Get the raw output data."""
85
+
86
+
67
87
  # classes for Agent responses
68
88
  ToolOutput = LI_ToolOutput
69
89
  AgentResponse = LI_AgentChatResponse
70
90
  AgentStreamingResponse = LI_StreamingAgentChatResponse
91
+ Document = LI_Document