lollms-client 0.29.3__py3-none-any.whl → 0.31.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 lollms-client might be problematic. Click here for more details.
- lollms_client/__init__.py +1 -1
- lollms_client/llm_bindings/ollama/__init__.py +19 -0
- lollms_client/lollms_core.py +115 -49
- lollms_client/lollms_discussion.py +428 -32
- lollms_client/lollms_llm_binding.py +17 -0
- lollms_client/lollms_utilities.py +136 -0
- {lollms_client-0.29.3.dist-info → lollms_client-0.31.0.dist-info}/METADATA +61 -222
- {lollms_client-0.29.3.dist-info → lollms_client-0.31.0.dist-info}/RECORD +12 -11
- {lollms_client-0.29.3.dist-info → lollms_client-0.31.0.dist-info}/top_level.txt +1 -0
- test/test_lollms_discussion.py +368 -0
- {lollms_client-0.29.3.dist-info → lollms_client-0.31.0.dist-info}/WHEEL +0 -0
- {lollms_client-0.29.3.dist-info → lollms_client-0.31.0.dist-info}/licenses/LICENSE +0 -0
lollms_client/__init__.py
CHANGED
|
@@ -8,7 +8,7 @@ from lollms_client.lollms_utilities import PromptReshaper # Keep general utiliti
|
|
|
8
8
|
from lollms_client.lollms_mcp_binding import LollmsMCPBinding, LollmsMCPBindingManager
|
|
9
9
|
from lollms_client.lollms_llm_binding import LollmsLLMBindingManager
|
|
10
10
|
|
|
11
|
-
__version__ = "0.
|
|
11
|
+
__version__ = "0.31.0" # Updated version
|
|
12
12
|
|
|
13
13
|
# Optionally, you could define __all__ if you want to be explicit about exports
|
|
14
14
|
__all__ = [
|
|
@@ -11,6 +11,7 @@ from typing import Optional, Callable, List, Union, Dict
|
|
|
11
11
|
|
|
12
12
|
from ascii_colors import ASCIIColors, trace_exception
|
|
13
13
|
import pipmaster as pm
|
|
14
|
+
from lollms_client.lollms_utilities import ImageTokenizer
|
|
14
15
|
pm.ensure_packages(["ollama","pillow","tiktoken"])
|
|
15
16
|
|
|
16
17
|
|
|
@@ -468,6 +469,24 @@ class OllamaBinding(LollmsLLMBinding):
|
|
|
468
469
|
return -1
|
|
469
470
|
#return count_tokens_ollama(text, self.model_name, self.ollama_client)
|
|
470
471
|
return len(self.tokenize(text))
|
|
472
|
+
|
|
473
|
+
def count_image_tokens(self, image: str) -> int:
|
|
474
|
+
"""
|
|
475
|
+
Estimate the number of tokens for an image using ImageTokenizer based on self.model_name.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
image (str): Image to count tokens from. Either base64 string, path to image file, or URL.
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
int: Estimated number of tokens for the image. Returns -1 on error.
|
|
482
|
+
"""
|
|
483
|
+
try:
|
|
484
|
+
# Delegate token counting to ImageTokenizer
|
|
485
|
+
return ImageTokenizer(self.model_name).count_image_tokens(image)
|
|
486
|
+
except Exception as e:
|
|
487
|
+
ASCIIColors.warning(f"Could not estimate image tokens: {e}")
|
|
488
|
+
return -1
|
|
489
|
+
|
|
471
490
|
def embed(self, text: str, **kwargs) -> List[float]:
|
|
472
491
|
"""
|
|
473
492
|
Get embeddings for the input text using Ollama API.
|
lollms_client/lollms_core.py
CHANGED
|
@@ -430,7 +430,21 @@ class LollmsClient():
|
|
|
430
430
|
if self.binding:
|
|
431
431
|
return self.binding.count_tokens(text)
|
|
432
432
|
raise RuntimeError("LLM binding not initialized.")
|
|
433
|
-
|
|
433
|
+
|
|
434
|
+
def count_image_tokens(self, image: str) -> int:
|
|
435
|
+
"""
|
|
436
|
+
Estimate the number of tokens for an image using ImageTokenizer based on self.model_name.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
image (str): Image to count tokens from. Either base64 string, path to image file, or URL.
|
|
440
|
+
|
|
441
|
+
Returns:
|
|
442
|
+
int: Estimated number of tokens for the image. Returns -1 on error.
|
|
443
|
+
"""
|
|
444
|
+
if self.binding:
|
|
445
|
+
return self.binding.count_image_tokens(image)
|
|
446
|
+
raise RuntimeError("LLM binding not initialized.")
|
|
447
|
+
|
|
434
448
|
def get_model_details(self) -> dict:
|
|
435
449
|
"""
|
|
436
450
|
Get model information from the active LLM binding.
|
|
@@ -1574,25 +1588,25 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
|
|
|
1574
1588
|
|
|
1575
1589
|
# Add the new put_code_in_buffer tool definition
|
|
1576
1590
|
available_tools.append({
|
|
1577
|
-
"name": "put_code_in_buffer",
|
|
1591
|
+
"name": "local_tools::put_code_in_buffer",
|
|
1578
1592
|
"description": """Generates and stores code into a buffer to be used by another tool. You can put the uuid of the generated code into the fields that require long code among the tools. If no tool requires code as input do not use put_code_in_buffer. put_code_in_buffer do not execute the code nor does it audit it.""",
|
|
1579
1593
|
"input_schema": {"type": "object", "properties": {"prompt": {"type": "string", "description": "A detailed natural language description of the code's purpose and requirements."}, "language": {"type": "string", "description": "The programming language of the generated code. By default it uses python."}}, "required": ["prompt"]}
|
|
1580
1594
|
})
|
|
1581
1595
|
available_tools.append({
|
|
1582
|
-
"name": "view_generated_code",
|
|
1596
|
+
"name": "local_tools::view_generated_code",
|
|
1583
1597
|
"description": """Views the code that was generated and stored to the buffer. You need to have a valid uuid of the generated code.""",
|
|
1584
1598
|
"input_schema": {"type": "object", "properties": {"code_id": {"type": "string", "description": "The case sensitive uuid of the generated code."}}, "required": ["uuid"]}
|
|
1585
1599
|
})
|
|
1586
1600
|
# Add the new refactor_scratchpad tool definition
|
|
1587
1601
|
available_tools.append({
|
|
1588
|
-
"name": "refactor_scratchpad",
|
|
1602
|
+
"name": "local_tools::refactor_scratchpad",
|
|
1589
1603
|
"description": "Rewrites the scratchpad content to clean it and reorganize it. Only use if the scratchpad is messy or contains too much information compared to what you need.",
|
|
1590
1604
|
"input_schema": {"type": "object", "properties": {}}
|
|
1591
1605
|
})
|
|
1592
1606
|
|
|
1593
1607
|
formatted_tools_list = "\n".join([f"**{t['name']}**:\n{t['description']}\ninput schema:\n{json.dumps(t['input_schema'])}" for t in available_tools])
|
|
1594
|
-
formatted_tools_list += "\n**request_clarification**:\nUse if the user's request is ambiguous and you can not infer a clear idea of his intent. this tool has no parameters."
|
|
1595
|
-
formatted_tools_list += "\n**final_answer**:\nUse when you are ready to respond to the user. this tool has no parameters."
|
|
1608
|
+
formatted_tools_list += "\n**local_tools::request_clarification**:\nUse if the user's request is ambiguous and you can not infer a clear idea of his intent. this tool has no parameters."
|
|
1609
|
+
formatted_tools_list += "\n**local_tools::final_answer**:\nUse when you are ready to respond to the user. this tool has no parameters."
|
|
1596
1610
|
|
|
1597
1611
|
if discovery_step_id: log_event(f"**Discovering tools** found {len(available_tools)} tools",MSG_TYPE.MSG_TYPE_STEP_END, event_id=discovery_step_id)
|
|
1598
1612
|
|
|
@@ -1618,15 +1632,16 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
|
|
|
1618
1632
|
- Does the latest observation completely fulfill the user's original request?
|
|
1619
1633
|
- If YES, your next action MUST be to use the `final_answer` tool.
|
|
1620
1634
|
- If NO, what is the single next logical step needed? This may involve writing code first with `put_code_in_buffer`, then using another tool.
|
|
1621
|
-
- If you are stuck or the request is ambiguous, use `request_clarification`.
|
|
1635
|
+
- If you are stuck or the request is ambiguous, use `local_tools::request_clarification`.
|
|
1622
1636
|
3. **ACT:** Formulate your decision as a JSON object.
|
|
1637
|
+
** Important ** Always use this format alias::tool_name to call the tool
|
|
1623
1638
|
"""
|
|
1624
1639
|
action_template = {
|
|
1625
1640
|
"thought": "My detailed analysis of the last observation and my reasoning for the next action and how it integrates with my global plan.",
|
|
1626
1641
|
"action": {
|
|
1627
|
-
"tool_name": "The single tool to use (e.g., 'put_code_in_buffer', '
|
|
1642
|
+
"tool_name": "The single tool to use (e.g., 'local_tools::put_code_in_buffer', 'local_tools::final_answer').",
|
|
1628
1643
|
"tool_params": {"param1": "value1"},
|
|
1629
|
-
"clarification_question": "(string, ONLY if tool_name is 'request_clarification')"
|
|
1644
|
+
"clarification_question": "(string, ONLY if tool_name is 'local_tools::request_clarification')"
|
|
1630
1645
|
}
|
|
1631
1646
|
}
|
|
1632
1647
|
if debug: log_prompt(reasoning_prompt_template, f"REASONING PROMPT (Step {i+1})")
|
|
@@ -1664,18 +1679,22 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
|
|
|
1664
1679
|
break
|
|
1665
1680
|
|
|
1666
1681
|
# --- Handle special, non-executing tools ---
|
|
1667
|
-
if tool_name == "request_clarification":
|
|
1682
|
+
if tool_name == "local_tools::request_clarification":
|
|
1668
1683
|
# Handle clarification...
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1684
|
+
if isinstance(action, dict):
|
|
1685
|
+
return {"final_answer": action.get("clarification_question", "Could you please provide more details?"), "final_scratchpad": current_scratchpad, "tool_calls": tool_calls_this_turn, "sources": sources_this_turn, "clarification_required": True, "error": None}
|
|
1686
|
+
elif isinstance(action, str):
|
|
1687
|
+
return {"final_answer": action, "final_scratchpad": current_scratchpad, "tool_calls": tool_calls_this_turn, "sources": sources_this_turn, "clarification_required": True, "error": None}
|
|
1688
|
+
else:
|
|
1689
|
+
return {"final_answer": "Could you please provide more details?", "final_scratchpad": current_scratchpad, "tool_calls": tool_calls_this_turn, "sources": sources_this_turn, "clarification_required": True, "error": None}
|
|
1690
|
+
if tool_name == "local_tools::final_answer":
|
|
1672
1691
|
current_scratchpad += f"\n\n### Step {i+1}: Action\n- **Action:** Decided to formulate the final answer."
|
|
1673
1692
|
log_event("**Action**: Formulate final answer.", MSG_TYPE.MSG_TYPE_THOUGHT_CHUNK)
|
|
1674
1693
|
if reasoning_step_id: log_event(f"**Reasoning Step {i+1}/{max_reasoning_steps}**",MSG_TYPE.MSG_TYPE_STEP_END, event_id=reasoning_step_id)
|
|
1675
1694
|
break
|
|
1676
1695
|
|
|
1677
1696
|
# --- Handle the `put_code_in_buffer` tool specifically ---
|
|
1678
|
-
if tool_name == 'put_code_in_buffer':
|
|
1697
|
+
if tool_name == 'local_tools::put_code_in_buffer':
|
|
1679
1698
|
code_gen_id = log_event(f"Generating code...", MSG_TYPE.MSG_TYPE_STEP_START, metadata={"name": "put_code_in_buffer", "id": "gencode"})
|
|
1680
1699
|
code_prompt = tool_params.get("prompt", "Generate the requested code.")
|
|
1681
1700
|
|
|
@@ -1694,7 +1713,7 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
|
|
|
1694
1713
|
if code_gen_id: log_event(f"Generating code...", MSG_TYPE.MSG_TYPE_TOOL_CALL, metadata={"id": code_gen_id, "result": tool_result})
|
|
1695
1714
|
if reasoning_step_id: log_event(f"**Reasoning Step {i+1}/{max_reasoning_steps}**", MSG_TYPE.MSG_TYPE_STEP_END, event_id= reasoning_step_id)
|
|
1696
1715
|
continue # Go to the next reasoning step immediately
|
|
1697
|
-
if tool_name == 'view_generated_code':
|
|
1716
|
+
if tool_name == 'local_tools::view_generated_code':
|
|
1698
1717
|
code_id = tool_params.get("code_id")
|
|
1699
1718
|
if code_id:
|
|
1700
1719
|
tool_result = {"status": "success", "code_id": code_id, "generated_code":generated_code_store[code_uuid]}
|
|
@@ -1704,7 +1723,7 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
|
|
|
1704
1723
|
current_scratchpad += f"\n\n### Step {i+1}: Observation\n- **Action:** Called `{tool_name}`\n- **Result:**\n{observation_text}"
|
|
1705
1724
|
log_event(f"Result from `{tool_name}`:\n```\n{generated_code_store[code_uuid]}\n```\n", MSG_TYPE.MSG_TYPE_TOOL_CALL, metadata={"id": code_gen_id, "result": tool_result})
|
|
1706
1725
|
continue
|
|
1707
|
-
if tool_name == 'refactor_scratchpad':
|
|
1726
|
+
if tool_name == 'local_tools::refactor_scratchpad':
|
|
1708
1727
|
scratchpad_cleaning_prompt = f"""Enhance this scratchpad content to be more organized and comprehensive. Keep relevant experience information and remove any useless redundancies. Try to log learned things from the context so that you won't make the same mistakes again. Do not remove the main objective information or any crucial information that may be useful for the next iterations. Answer directly with the new scratchpad content without any comments.
|
|
1709
1728
|
--- YOUR INTERNAL SCRATCHPAD (Work History & Analysis) ---
|
|
1710
1729
|
{current_scratchpad}
|
|
@@ -2958,12 +2977,12 @@ Provide the final aggregated answer in {output_format} format, directly addressi
|
|
|
2958
2977
|
callback("Deep analysis complete.", MSG_TYPE.MSG_TYPE_STEP_END)
|
|
2959
2978
|
return final_output
|
|
2960
2979
|
|
|
2961
|
-
def
|
|
2980
|
+
def long_context_processing(
|
|
2962
2981
|
self,
|
|
2963
|
-
|
|
2982
|
+
text_to_process: str,
|
|
2964
2983
|
contextual_prompt: Optional[str] = None,
|
|
2965
|
-
chunk_size_tokens: int =
|
|
2966
|
-
overlap_tokens: int =
|
|
2984
|
+
chunk_size_tokens: int|None = None,
|
|
2985
|
+
overlap_tokens: int = 0,
|
|
2967
2986
|
streaming_callback: Optional[Callable] = None,
|
|
2968
2987
|
**kwargs
|
|
2969
2988
|
) -> str:
|
|
@@ -2975,7 +2994,7 @@ Provide the final aggregated answer in {output_format} format, directly addressi
|
|
|
2975
2994
|
2. **Synthesize:** It then takes all the chunk summaries and performs a final summarization pass to create a single, coherent, and comprehensive summary.
|
|
2976
2995
|
|
|
2977
2996
|
Args:
|
|
2978
|
-
|
|
2997
|
+
text_to_process (str): The long text content to be summarized.
|
|
2979
2998
|
contextual_prompt (Optional[str], optional): A specific instruction to guide the summary's focus.
|
|
2980
2999
|
For example, "Summarize the text focusing on the financial implications."
|
|
2981
3000
|
Defaults to None.
|
|
@@ -2993,25 +3012,40 @@ Provide the final aggregated answer in {output_format} format, directly addressi
|
|
|
2993
3012
|
Returns:
|
|
2994
3013
|
str: The final, comprehensive summary of the text.
|
|
2995
3014
|
"""
|
|
2996
|
-
if not
|
|
3015
|
+
if not text_to_process and len(kwargs.get("images",[]))==0:
|
|
2997
3016
|
return ""
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3017
|
+
if not text_to_process:
|
|
3018
|
+
text_to_process=""
|
|
3019
|
+
tokens = []
|
|
3020
|
+
else:
|
|
3021
|
+
# Use the binding's tokenizer for accurate chunking
|
|
3022
|
+
tokens = self.binding.tokenize(text_to_process)
|
|
3023
|
+
if chunk_size_tokens is None:
|
|
3024
|
+
chunk_size_tokens = self.default_ctx_size//2
|
|
3001
3025
|
|
|
3002
3026
|
if len(tokens) <= chunk_size_tokens:
|
|
3003
3027
|
if streaming_callback:
|
|
3004
|
-
streaming_callback("Text is short enough for a single
|
|
3028
|
+
streaming_callback("Text is short enough for a single process.", MSG_TYPE.MSG_TYPE_STEP, {"progress": 0})
|
|
3029
|
+
system_prompt = ("You are a content processor expert.\n"
|
|
3030
|
+
"You perform tasks on the content as requested by the user.\n\n"
|
|
3031
|
+
"--- Content ---\n"
|
|
3032
|
+
f"{text_to_process}\n\n"
|
|
3033
|
+
"** Important **\n"
|
|
3034
|
+
"Strictly adhere to the user prompt.\n"
|
|
3035
|
+
"Do not add comments unless asked to do so.\n"
|
|
3036
|
+
)
|
|
3037
|
+
if "system_prompt" in kwargs:
|
|
3038
|
+
system_prompt += "-- Extra instructions --\n"+ kwargs["system_prompt"] +"\n"
|
|
3039
|
+
del kwargs["system_prompt"]
|
|
3040
|
+
prompt_objective = contextual_prompt or "Provide a comprehensive summary of the content."
|
|
3041
|
+
final_prompt = f"{prompt_objective}"
|
|
3005
3042
|
|
|
3006
|
-
|
|
3007
|
-
final_prompt = f"{prompt_objective}\n\n--- Text to Summarize ---\n{text_to_summarize}"
|
|
3008
|
-
|
|
3009
|
-
summary = self.generate_text(final_prompt, **kwargs)
|
|
3043
|
+
processed_output = self.generate_text(final_prompt, system_prompt=system_prompt, **kwargs)
|
|
3010
3044
|
|
|
3011
3045
|
if streaming_callback:
|
|
3012
|
-
streaming_callback("
|
|
3046
|
+
streaming_callback("Content processed.", MSG_TYPE.MSG_TYPE_STEP, {"progress": 100})
|
|
3013
3047
|
|
|
3014
|
-
return
|
|
3048
|
+
return processed_output
|
|
3015
3049
|
|
|
3016
3050
|
# --- Stage 1: Chunking and Independent Summarization ---
|
|
3017
3051
|
chunks = []
|
|
@@ -3028,43 +3062,62 @@ Provide the final aggregated answer in {output_format} format, directly addressi
|
|
|
3028
3062
|
|
|
3029
3063
|
# Define the prompt for summarizing each chunk
|
|
3030
3064
|
summarization_objective = contextual_prompt or "Summarize the key points of the following text excerpt."
|
|
3031
|
-
|
|
3065
|
+
system_prompt = ("You are a sequential document processing agent.\n"
|
|
3066
|
+
"The process is done in two phases:\n"
|
|
3067
|
+
"** Phase1 : **\n"
|
|
3068
|
+
"Sequencially extracting information from the text chunks and adding them to the scratchpad.\n"
|
|
3069
|
+
"** Phase2: **\n"
|
|
3070
|
+
"Synthesizing a comprehensive Response using the scratchpad content given the objective formatting instructions if applicable.\n"
|
|
3071
|
+
"We are now performing ** Phase 1 **, and we are processing chunk number {{chunk_id}}.\n"
|
|
3072
|
+
"Your job is to extract information from the current chunk given previous chunks extracted information placed in scratchpad as well as the current chunk content.\n"
|
|
3073
|
+
"Add the information to the scratchpad while strictly adhering to the Global objective extraction instructions:\n"
|
|
3074
|
+
"-- Sequencial Scratchpad --\n"
|
|
3075
|
+
"{{scratchpad}}\n"
|
|
3076
|
+
"** Important **\n"
|
|
3077
|
+
"Respond only with the extracted information from the current chunk without repeating things that are already in the scratchpad.\n"
|
|
3078
|
+
"Strictly adhere to the Global objective content for the extraction phase.\n"
|
|
3079
|
+
"Do not add comments.\n"
|
|
3080
|
+
)
|
|
3081
|
+
if "system_prompt" in kwargs:
|
|
3082
|
+
system_prompt += "-- Extra instructions --\n"+ kwargs["system_prompt"] +"\n"
|
|
3083
|
+
del kwargs["system_prompt"]
|
|
3084
|
+
chunk_summary_prompt_template = f"--- Global objective ---\n{summarization_objective}\n\n--- Text Excerpt ---\n{{chunk_text}}"
|
|
3032
3085
|
|
|
3033
3086
|
for i, chunk in enumerate(chunks):
|
|
3034
3087
|
progress_before = (i / total_steps) * 100
|
|
3035
3088
|
if streaming_callback:
|
|
3036
3089
|
streaming_callback(
|
|
3037
|
-
f"
|
|
3090
|
+
f"Processing chunk {i + 1} of {len(chunks)}...",
|
|
3038
3091
|
MSG_TYPE.MSG_TYPE_STEP_START,
|
|
3039
3092
|
{"id": f"chunk_{i+1}", "progress": progress_before}
|
|
3040
3093
|
)
|
|
3041
3094
|
|
|
3042
3095
|
prompt = chunk_summary_prompt_template.format(chunk_text=chunk)
|
|
3043
|
-
|
|
3096
|
+
processed_system_prompt = system_prompt.format(chunk_id=i,scratchpad="\n\n---\n\n".join(chunk_summaries))
|
|
3044
3097
|
try:
|
|
3045
3098
|
# Generate summary for the current chunk
|
|
3046
|
-
chunk_summary = self.generate_text(prompt, **kwargs)
|
|
3099
|
+
chunk_summary = self.generate_text(prompt, system_prompt=processed_system_prompt, **kwargs)
|
|
3047
3100
|
chunk_summaries.append(chunk_summary)
|
|
3048
3101
|
|
|
3049
3102
|
progress_after = ((i + 1) / total_steps) * 100
|
|
3050
3103
|
if streaming_callback:
|
|
3051
3104
|
streaming_callback(
|
|
3052
|
-
f"Chunk {i + 1}
|
|
3105
|
+
f"Chunk {i + 1} processed. Progress: {progress_after:.0f}%",
|
|
3053
3106
|
MSG_TYPE.MSG_TYPE_STEP_END,
|
|
3054
|
-
{"id": f"chunk_{i+1}", "
|
|
3107
|
+
{"id": f"chunk_{i+1}", "output_snippet": chunk_summary[:100], "progress": progress_after}
|
|
3055
3108
|
)
|
|
3056
3109
|
except Exception as e:
|
|
3057
3110
|
trace_exception(e)
|
|
3058
3111
|
if streaming_callback:
|
|
3059
|
-
streaming_callback(f"Failed to
|
|
3112
|
+
streaming_callback(f"Failed to process chunk {i+1}: {e}", MSG_TYPE.MSG_TYPE_EXCEPTION)
|
|
3060
3113
|
# Still add a placeholder to not break the chain
|
|
3061
|
-
chunk_summaries.append(f"[Error
|
|
3114
|
+
chunk_summaries.append(f"[Error processing chunk {i+1}]")
|
|
3062
3115
|
|
|
3063
3116
|
# --- Stage 2: Final Synthesis of All Chunk Summaries ---
|
|
3064
3117
|
progress_before_synthesis = (len(chunks) / total_steps) * 100
|
|
3065
3118
|
if streaming_callback:
|
|
3066
3119
|
streaming_callback(
|
|
3067
|
-
"
|
|
3120
|
+
"Processing the scratchpad content into a final version...",
|
|
3068
3121
|
MSG_TYPE.MSG_TYPE_STEP_START,
|
|
3069
3122
|
{"id": "final_synthesis", "progress": progress_before_synthesis}
|
|
3070
3123
|
)
|
|
@@ -3073,16 +3126,29 @@ Provide the final aggregated answer in {output_format} format, directly addressi
|
|
|
3073
3126
|
|
|
3074
3127
|
# Define the prompt for the final synthesis
|
|
3075
3128
|
synthesis_objective = contextual_prompt or "Create a single, final, coherent, and comprehensive summary."
|
|
3129
|
+
system_prompt = ("You are a sequential document processing agent.\n"
|
|
3130
|
+
"The process is done in two phases:\n"
|
|
3131
|
+
"** Phase1 : **\n"
|
|
3132
|
+
"Sequencially extracting information from the text chunks and adding them to the scratchpad.\n"
|
|
3133
|
+
"** Phase2: **\n"
|
|
3134
|
+
"Synthesizing a comprehensive Response using the scratchpad content given the objective formatting instructions if applicable.\n"
|
|
3135
|
+
"\n"
|
|
3136
|
+
"We are now performing ** Phase 2 **.\n"
|
|
3137
|
+
"Your job is to use the extracted information to fulfill the user prompt objectives.\n"
|
|
3138
|
+
"Make sure you respect the user formatting if provided and if not, then use markdown output format."
|
|
3139
|
+
"-- Sequencial Scratchpad --\n"
|
|
3140
|
+
f"{combined_summaries}\n"
|
|
3141
|
+
"** Important **\n"
|
|
3142
|
+
"Respond only with the requested task without extra comments unless told to.\n"
|
|
3143
|
+
"Strictly adhere to the Global objective content for the extraction phase.\n"
|
|
3144
|
+
"Do not add comments.\n"
|
|
3145
|
+
)
|
|
3076
3146
|
final_synthesis_prompt = (
|
|
3077
|
-
"
|
|
3078
|
-
|
|
3079
|
-
"Please remove any redundancy and ensure a smooth, logical flow.\n\n"
|
|
3080
|
-
"--- Collection of Summaries ---\n"
|
|
3081
|
-
f"{combined_summaries}\n\n"
|
|
3082
|
-
"--- Final Comprehensive Summary ---"
|
|
3147
|
+
f"--- Global objective ---\n{synthesis_objective}\n\n"
|
|
3148
|
+
"--- Final Response ---"
|
|
3083
3149
|
)
|
|
3084
3150
|
|
|
3085
|
-
|
|
3151
|
+
final_answer = self.generate_text(final_synthesis_prompt, system_prompt=system_prompt, **kwargs)
|
|
3086
3152
|
|
|
3087
3153
|
if streaming_callback:
|
|
3088
3154
|
streaming_callback(
|
|
@@ -3091,7 +3157,7 @@ Provide the final aggregated answer in {output_format} format, directly addressi
|
|
|
3091
3157
|
{"id": "final_synthesis", "progress": 100}
|
|
3092
3158
|
)
|
|
3093
3159
|
|
|
3094
|
-
return
|
|
3160
|
+
return final_answer.strip()
|
|
3095
3161
|
|
|
3096
3162
|
def chunk_text(text, tokenizer, detokenizer, chunk_size, overlap, use_separators=True):
|
|
3097
3163
|
"""
|