biblemateagent 0.1.0__tar.gz
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.
- biblemateagent-0.1.0/PKG-INFO +65 -0
- biblemateagent-0.1.0/README.md +26 -0
- biblemateagent-0.1.0/biblemateagent/README.md +26 -0
- biblemateagent-0.1.0/biblemateagent/agent.py +269 -0
- biblemateagent-0.1.0/biblemateagent/config.py +0 -0
- biblemateagent-0.1.0/biblemateagent/main.py +20 -0
- biblemateagent-0.1.0/biblemateagent/package_name.txt +1 -0
- biblemateagent-0.1.0/biblemateagent/requirements.txt +1 -0
- biblemateagent-0.1.0/biblemateagent/stream.py +125 -0
- biblemateagent-0.1.0/biblemateagent/version.txt +1 -0
- biblemateagent-0.1.0/biblemateagent.egg-info/PKG-INFO +65 -0
- biblemateagent-0.1.0/biblemateagent.egg-info/SOURCES.txt +16 -0
- biblemateagent-0.1.0/biblemateagent.egg-info/dependency_links.txt +1 -0
- biblemateagent-0.1.0/biblemateagent.egg-info/entry_points.txt +4 -0
- biblemateagent-0.1.0/biblemateagent.egg-info/requires.txt +4 -0
- biblemateagent-0.1.0/biblemateagent.egg-info/top_level.txt +1 -0
- biblemateagent-0.1.0/setup.cfg +4 -0
- biblemateagent-0.1.0/setup.py +96 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: biblemateagent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: BibleMate AI - Automate Your Bible Study; A headless version of BibleMate AI Agent Mode
|
|
5
|
+
Home-page: https://biblemate.ai
|
|
6
|
+
Author: Eliran Wong
|
|
7
|
+
Author-email: support@marvel.bible
|
|
8
|
+
License: GNU General Public License (GPL)
|
|
9
|
+
Project-URL: Source, https://github.com/eliranwong/biblemateagent
|
|
10
|
+
Project-URL: Tracker, https://github.com/eliranwong/biblemateagent/issues
|
|
11
|
+
Project-URL: Documentation, https://github.com/eliranwong/biblemateagent/wiki
|
|
12
|
+
Project-URL: Funding, https://www.paypal.me/MarvelBible
|
|
13
|
+
Keywords: mcp agent biblemate ai anthropic azure chatgpt cohere deepseek genai github googleai groq llamacpp mistral ollama openai vertexai xai
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: Topic :: Utilities
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
19
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Requires-Python: >=3.10, <3.13
|
|
24
|
+
Requires-Dist: biblemateweb>=0.3.56
|
|
25
|
+
Provides-Extra: genai
|
|
26
|
+
Requires-Dist: google-genai>=1.46.0; extra == "genai"
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: keywords
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: project-url
|
|
35
|
+
Dynamic: provides-extra
|
|
36
|
+
Dynamic: requires-dist
|
|
37
|
+
Dynamic: requires-python
|
|
38
|
+
Dynamic: summary
|
|
39
|
+
|
|
40
|
+
# biblemateagent
|
|
41
|
+
A headless version of BibleMate AI Agent Mode
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
> pip install biblemateagent
|
|
46
|
+
|
|
47
|
+
## Set up data
|
|
48
|
+
|
|
49
|
+
> biblematedata
|
|
50
|
+
|
|
51
|
+
## Run BibleMate Agent
|
|
52
|
+
|
|
53
|
+
> biblemateagent "Your Bible Study Request"
|
|
54
|
+
|
|
55
|
+
or
|
|
56
|
+
|
|
57
|
+
> bibleagent "Your Bible Study Request"
|
|
58
|
+
|
|
59
|
+
## Help
|
|
60
|
+
|
|
61
|
+
> biblemateagent -h
|
|
62
|
+
|
|
63
|
+
or
|
|
64
|
+
|
|
65
|
+
> bibleagent -h
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# biblemateagent
|
|
2
|
+
A headless version of BibleMate AI Agent Mode
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
|
|
6
|
+
> pip install biblemateagent
|
|
7
|
+
|
|
8
|
+
## Set up data
|
|
9
|
+
|
|
10
|
+
> biblematedata
|
|
11
|
+
|
|
12
|
+
## Run BibleMate Agent
|
|
13
|
+
|
|
14
|
+
> biblemateagent "Your Bible Study Request"
|
|
15
|
+
|
|
16
|
+
or
|
|
17
|
+
|
|
18
|
+
> bibleagent "Your Bible Study Request"
|
|
19
|
+
|
|
20
|
+
## Help
|
|
21
|
+
|
|
22
|
+
> biblemateagent -h
|
|
23
|
+
|
|
24
|
+
or
|
|
25
|
+
|
|
26
|
+
> bibleagent -h
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# biblemateagent
|
|
2
|
+
A headless version of BibleMate AI Agent Mode
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
|
|
6
|
+
> pip install biblemateagent
|
|
7
|
+
|
|
8
|
+
## Set up data
|
|
9
|
+
|
|
10
|
+
> biblematedata
|
|
11
|
+
|
|
12
|
+
## Run BibleMate Agent
|
|
13
|
+
|
|
14
|
+
> biblemateagent "Your Bible Study Request"
|
|
15
|
+
|
|
16
|
+
or
|
|
17
|
+
|
|
18
|
+
> bibleagent "Your Bible Study Request"
|
|
19
|
+
|
|
20
|
+
## Help
|
|
21
|
+
|
|
22
|
+
> biblemateagent -h
|
|
23
|
+
|
|
24
|
+
or
|
|
25
|
+
|
|
26
|
+
> bibleagent -h
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import datetime
|
|
3
|
+
import re
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
import pypandoc
|
|
7
|
+
import traceback
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
|
|
10
|
+
from biblemateagent.stream import stream_response_headless
|
|
11
|
+
from biblemateweb import BIBLEMATEWEB_APP_DIR, get_translation, DEFAULT_MESSAGES, chapter2verses
|
|
12
|
+
from biblemateweb.mcp_tools.elements import TOOL_ELEMENTS
|
|
13
|
+
from biblemateweb.mcp_tools.tools import TOOLS
|
|
14
|
+
from biblemateweb.mcp_tools.tool_descriptions import TOOL_DESCRIPTIONS
|
|
15
|
+
from biblemateweb.api.api import get_api_content
|
|
16
|
+
from biblemate.core.systems import get_system_tool_instruction, get_system_master_plan, get_system_make_suggestion, get_system_progress, get_system_generate_title
|
|
17
|
+
from agentmake import agentmake, readTextFile, getCurrentDateTime
|
|
18
|
+
|
|
19
|
+
def do_export(content, filename, export_md=True, export_docx=False, output_directory=None):
|
|
20
|
+
|
|
21
|
+
if not os.path.isdir(output_directory):
|
|
22
|
+
os.makedirs(output_directory)
|
|
23
|
+
|
|
24
|
+
if export_md:
|
|
25
|
+
md_filepath = os.path.join(output_directory, f"{filename}.md")
|
|
26
|
+
with open(md_filepath, "w", encoding="utf-8") as f:
|
|
27
|
+
f.write(content)
|
|
28
|
+
print(f"Exported to: {md_filepath}")
|
|
29
|
+
|
|
30
|
+
if export_docx:
|
|
31
|
+
if not shutil.which("pandoc"):
|
|
32
|
+
print("Pandoc is not installed. Skipping DOCX export.")
|
|
33
|
+
return
|
|
34
|
+
try:
|
|
35
|
+
docx_filepath = os.path.join(output_directory, f"{filename}.docx")
|
|
36
|
+
pypandoc.convert_text(content, 'docx', format='md', outputfile=docx_filepath)
|
|
37
|
+
print(f"Exported to: {docx_filepath}")
|
|
38
|
+
except ImportError:
|
|
39
|
+
print("pypandoc not installed. Skipping DOCX export.")
|
|
40
|
+
except Exception as e:
|
|
41
|
+
print(f"Error exporting to DOCX: {e}")
|
|
42
|
+
|
|
43
|
+
async def ai_agent_headless(q="", ui_language="eng", improve_prompt=False, export_md=False, export_docx=False, output_directory=None, cancel_event=None, developer=False, **kwargs):
|
|
44
|
+
|
|
45
|
+
if output_directory is None:
|
|
46
|
+
output_directory = os.getcwd()
|
|
47
|
+
|
|
48
|
+
MESSAGES = None
|
|
49
|
+
MASTER_PLAN = None
|
|
50
|
+
PROGRESS_STATUS = None
|
|
51
|
+
ROUND = 1
|
|
52
|
+
MASTER_USER_REQUEST = q
|
|
53
|
+
|
|
54
|
+
SYSTEM_TOOL_SELECTION = readTextFile(os.path.join(BIBLEMATEWEB_APP_DIR, "mcp_tools", "system_tool_selection_lite.md"))
|
|
55
|
+
|
|
56
|
+
TOOL_INSTRUCTION_PROMPT = """Please transform the following suggestions into clear, precise, and actionable instructions."""
|
|
57
|
+
TOOL_INSTRUCTION_SUFFIX = """
|
|
58
|
+
|
|
59
|
+
# Remember
|
|
60
|
+
|
|
61
|
+
* Provide me with the instructions directly.
|
|
62
|
+
* Do not start your response, like, 'Here are the insturctions ...'
|
|
63
|
+
* Do not ask me if I want to execute the instruction."""
|
|
64
|
+
|
|
65
|
+
MASTER_PLAN_PROMPT_TEMPLATE = """Provide me with the `Preliminary Action Plan` and the `Measurable Outcome` for resolving `My Request`.
|
|
66
|
+
|
|
67
|
+
# Available Tools
|
|
68
|
+
|
|
69
|
+
Available tools are: {available_tools}.
|
|
70
|
+
|
|
71
|
+
{tool_descriptions}
|
|
72
|
+
|
|
73
|
+
# My Request
|
|
74
|
+
|
|
75
|
+
{user_request}"""
|
|
76
|
+
|
|
77
|
+
FINAL_INSTRUCTION = """# Instruction
|
|
78
|
+
Please provide a comprehensive response that resolves my original request, ensuring all previously completed milestones and data points are fully integrated.
|
|
79
|
+
|
|
80
|
+
# Original Request
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
if not q or not q.strip():
|
|
84
|
+
print("Please provide a request.")
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
timestamp = getCurrentDateTime()
|
|
88
|
+
generated_title = ""
|
|
89
|
+
generated_title_output = agentmake(MASTER_USER_REQUEST, system=get_system_generate_title(), **kwargs)
|
|
90
|
+
if generated_title_output:
|
|
91
|
+
generated_title = generated_title_output[-1].get("content", "").strip().replace("Title: ", "")
|
|
92
|
+
print(f"\n[TITLE] {generated_title}\n")
|
|
93
|
+
study_directory = f"{timestamp}_{generated_title}"
|
|
94
|
+
output_directory = os.path.join(output_directory, study_directory)
|
|
95
|
+
else:
|
|
96
|
+
study_directory = f"{timestamp}_bible_study"
|
|
97
|
+
output_directory = os.path.join(output_directory, study_directory)
|
|
98
|
+
|
|
99
|
+
print(f"\n[REQUEST] {MASTER_USER_REQUEST}\n")
|
|
100
|
+
|
|
101
|
+
MESSAGES = deepcopy(DEFAULT_MESSAGES)
|
|
102
|
+
|
|
103
|
+
if improve_prompt:
|
|
104
|
+
print("\n--- Improving Prompt ---\n")
|
|
105
|
+
user_request = await stream_response_headless(
|
|
106
|
+
MESSAGES, MASTER_USER_REQUEST, cancel_event, system="improve_prompt_2"
|
|
107
|
+
)
|
|
108
|
+
if user_request and user_request.strip() != "[NO_CONTENT]":
|
|
109
|
+
if "```" in user_request:
|
|
110
|
+
MASTER_USER_REQUEST = re.sub(r"^.*?(```improved_prompt|```)(.+?)```.*?$", r"\2", user_request, flags=re.DOTALL).strip()
|
|
111
|
+
else:
|
|
112
|
+
MASTER_USER_REQUEST = user_request.strip()
|
|
113
|
+
print(f"\n[IMPROVED REQUEST] {MASTER_USER_REQUEST}\n")
|
|
114
|
+
|
|
115
|
+
MESSAGES += [
|
|
116
|
+
{"role": "user", "content": MASTER_USER_REQUEST},
|
|
117
|
+
{"role": "assistant", "content": "Let's begin!"},
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
# Generate master plan
|
|
121
|
+
print("\n--- Generating Study Plan ---\n")
|
|
122
|
+
master_plan_prompt = MASTER_PLAN_PROMPT_TEMPLATE.format(
|
|
123
|
+
available_tools=list(TOOLS.keys()),
|
|
124
|
+
tool_descriptions=TOOL_DESCRIPTIONS,
|
|
125
|
+
user_request=MASTER_USER_REQUEST
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
MASTER_PLAN = await stream_response_headless(
|
|
129
|
+
MESSAGES, master_plan_prompt, cancel_event, system=get_system_master_plan()
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if not MASTER_PLAN or MASTER_PLAN.strip() == "[NO_CONTENT]":
|
|
133
|
+
print("Failed to generate master plan.")
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
if export_md or export_docx:
|
|
137
|
+
filename = f"00_request_and_master_plan"
|
|
138
|
+
content = f"# Title\n\n{generated_title}\n\n" if generated_title else ""
|
|
139
|
+
content += f"# Request\n\n{MASTER_USER_REQUEST}\n\n# Master Plan\n\n{MASTER_PLAN}"
|
|
140
|
+
do_export(content, filename, export_md, export_docx, output_directory)
|
|
141
|
+
|
|
142
|
+
PROGRESS_STATUS = "START"
|
|
143
|
+
print("\n--- Finished generating study plan. Beginning rounds. ---\n")
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
while PROGRESS_STATUS is None or not ("STOP" in PROGRESS_STATUS or re.sub("^[^A-Za-z]*?([A-Za-z]+?)[^A-Za-z]*?$", r"\1", PROGRESS_STATUS).upper() == "STOP"):
|
|
147
|
+
if cancel_event and cancel_event.is_set():
|
|
148
|
+
break
|
|
149
|
+
|
|
150
|
+
print(f"\n### Round {ROUND} ###\n")
|
|
151
|
+
|
|
152
|
+
# suggestion
|
|
153
|
+
print("\n--- Suggestion ---\n")
|
|
154
|
+
system_make_suggestion = get_system_make_suggestion(master_plan=MASTER_PLAN)
|
|
155
|
+
follow_up_prompt = "Please provide me with the next step suggestion, based on the action plan."
|
|
156
|
+
|
|
157
|
+
suggestion = await stream_response_headless(MESSAGES, follow_up_prompt, cancel_event, system=system_make_suggestion)
|
|
158
|
+
|
|
159
|
+
if not suggestion or suggestion.strip() == "[NO_CONTENT]":
|
|
160
|
+
print("\n[No suggestion generated. Stopping.]\n")
|
|
161
|
+
break
|
|
162
|
+
|
|
163
|
+
# tool selection
|
|
164
|
+
print("\n--- Tool Selection ---\n")
|
|
165
|
+
suggested_tools = await stream_response_headless(DEFAULT_MESSAGES, suggestion, cancel_event, system=SYSTEM_TOOL_SELECTION)
|
|
166
|
+
|
|
167
|
+
if not suggested_tools or suggested_tools.strip() == "[NO_CONTENT]":
|
|
168
|
+
suggested_tools_list = ["get_direct_text_response"]
|
|
169
|
+
else:
|
|
170
|
+
try:
|
|
171
|
+
suggested_tools_str = re.sub(r"^.*?(\[.*?\]).*?$", r"\1", suggested_tools, flags=re.DOTALL)
|
|
172
|
+
suggested_tools_list = eval(suggested_tools_str.replace("`", "'")) if suggested_tools_str.startswith("[") and suggested_tools_str.endswith("]") else ["get_direct_text_response"]
|
|
173
|
+
except:
|
|
174
|
+
suggested_tools_list = ["get_direct_text_response"]
|
|
175
|
+
|
|
176
|
+
selected_tool = suggested_tools_list[0] if suggested_tools_list else "get_direct_text_response"
|
|
177
|
+
if not selected_tool in TOOLS:
|
|
178
|
+
selected_tool = "get_direct_text_response"
|
|
179
|
+
|
|
180
|
+
print(f"\n[Selected Tool: {selected_tool}]\n")
|
|
181
|
+
|
|
182
|
+
# tool instruction
|
|
183
|
+
print("\n--- Tool Instruction ---\n")
|
|
184
|
+
selected_tool_description = TOOLS.get(selected_tool, "No description available.")
|
|
185
|
+
tool_instruction_draft = TOOL_INSTRUCTION_PROMPT + "\n\n# Suggestions\n\n"+suggestion+f"\n\n# Tool Description of `{selected_tool}`\n\n"+selected_tool_description+TOOL_INSTRUCTION_SUFFIX
|
|
186
|
+
system_tool_instruction = get_system_tool_instruction(selected_tool, selected_tool_description)
|
|
187
|
+
|
|
188
|
+
user_request = await stream_response_headless(MESSAGES, tool_instruction_draft, cancel_event, system=system_tool_instruction)
|
|
189
|
+
|
|
190
|
+
if not user_request or user_request.strip() == "[NO_CONTENT]":
|
|
191
|
+
print("\n[No tool instruction generated. Stopping.]\n")
|
|
192
|
+
break
|
|
193
|
+
|
|
194
|
+
print("\n--- Agent Execution ---\n")
|
|
195
|
+
answers = None
|
|
196
|
+
try:
|
|
197
|
+
if selected_tool == "get_direct_text_response":
|
|
198
|
+
answers = await stream_response_headless(MESSAGES, user_request, cancel_event, system="auto")
|
|
199
|
+
else:
|
|
200
|
+
element = TOOL_ELEMENTS.get(selected_tool)
|
|
201
|
+
if isinstance(element, str):
|
|
202
|
+
print(f"Loading {selected_tool}...")
|
|
203
|
+
if not selected_tool == "search_the_whole_bible":
|
|
204
|
+
user_req = chapter2verses(user_request)
|
|
205
|
+
else:
|
|
206
|
+
user_req = user_request
|
|
207
|
+
api_query = f"{element}{user_req}"
|
|
208
|
+
answers = await asyncio.to_thread(get_api_content, api_query, ui_language)
|
|
209
|
+
if answers:
|
|
210
|
+
print(answers)
|
|
211
|
+
else:
|
|
212
|
+
answers = "[NO_CONTENT]"
|
|
213
|
+
print(answers)
|
|
214
|
+
elif isinstance(element, dict):
|
|
215
|
+
system = element.pop("system") if "system" in element else None
|
|
216
|
+
answers = await stream_response_headless(MESSAGES, user_request, cancel_event, system=system, **element)
|
|
217
|
+
|
|
218
|
+
except Exception as e:
|
|
219
|
+
answers = f"[{get_translation('Error')}: {str(e)}]"
|
|
220
|
+
print(f"\n{answers}\n")
|
|
221
|
+
if developer:
|
|
222
|
+
traceback.print_exc()
|
|
223
|
+
|
|
224
|
+
if answers and not (answers.strip() == "[NO_CONTENT]" or answers.startswith("[Error:")):
|
|
225
|
+
if export_md or export_docx:
|
|
226
|
+
round_str = f"{ROUND:02}"
|
|
227
|
+
filename = f"{round_str}_{selected_tool}"
|
|
228
|
+
do_export(answers, filename, export_md, export_docx, output_directory)
|
|
229
|
+
MESSAGES += [
|
|
230
|
+
{"role": "user", "content": f"[ROUND {ROUND}]\n\n{user_request}"},
|
|
231
|
+
{"role": "assistant", "content": f"[TOOL] {selected_tool}\n\n[RESPONSE]\n\n{answers}"},
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
# check progress
|
|
235
|
+
print("\n--- Progress Check ---\n")
|
|
236
|
+
system_progress = get_system_progress(master_plan=MASTER_PLAN)
|
|
237
|
+
follow_up_prompt="Please decide either to `CONTINUE` or `STOP` the process."
|
|
238
|
+
PROGRESS_STATUS = await stream_response_headless(MESSAGES, follow_up_prompt, cancel_event, system=system_progress)
|
|
239
|
+
|
|
240
|
+
if not PROGRESS_STATUS or PROGRESS_STATUS.strip() == "[NO_CONTENT]":
|
|
241
|
+
MESSAGES = MESSAGES[:-2]
|
|
242
|
+
break
|
|
243
|
+
|
|
244
|
+
ROUND += 1
|
|
245
|
+
|
|
246
|
+
print("\n---\n")
|
|
247
|
+
print("\nWrapping up...\n")
|
|
248
|
+
print("\n--- Final Report ---\n")
|
|
249
|
+
system_report = "write_final_answer"
|
|
250
|
+
follow_up_prompt=f"""{FINAL_INSTRUCTION}{MASTER_USER_REQUEST}"""
|
|
251
|
+
report = await stream_response_headless(MESSAGES, follow_up_prompt, cancel_event, system=system_report)
|
|
252
|
+
|
|
253
|
+
if report and report.strip() != "[NO_CONTENT]":
|
|
254
|
+
if export_md or export_docx:
|
|
255
|
+
round_str = f"{ROUND:02}"
|
|
256
|
+
filename = f"{round_str}_final_report"
|
|
257
|
+
do_export(report, filename, export_md, export_docx, output_directory)
|
|
258
|
+
MESSAGES += [
|
|
259
|
+
{"role": "user", "content": "[FINAL] Please provide a comprehensive response that resolves my original request, ensuring all previously completed milestones and data points are fully integrated."},
|
|
260
|
+
{"role": "assistant", "content": f"[REPORT]\n\n{report}"},
|
|
261
|
+
]
|
|
262
|
+
print("\n--- Finished successfully ---\n")
|
|
263
|
+
|
|
264
|
+
return MESSAGES
|
|
265
|
+
|
|
266
|
+
except Exception as e:
|
|
267
|
+
print(f"\nError: {e}\n")
|
|
268
|
+
# traceback.print_exc()
|
|
269
|
+
return None
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import asyncio, argparse
|
|
2
|
+
from biblemateagent.agent import ai_agent_headless
|
|
3
|
+
|
|
4
|
+
parser = argparse.ArgumentParser(description = f"""BibleMate AI Agent""")
|
|
5
|
+
parser.add_argument("default", nargs="*", default=None, help="user query")
|
|
6
|
+
parser.add_argument("-l", "--language", action="store", dest="language", help="language option; `eng` by defatul; set this option to `tc` or `sc` to override")
|
|
7
|
+
parser.add_argument("-t", "--token", action="store", dest="token", help=f"custom token to get acccess to custom data")
|
|
8
|
+
parser.add_argument("-u", "--url", action="store", dest="url", help=f"custom token to get acccess to custom data")
|
|
9
|
+
args = parser.parse_args()
|
|
10
|
+
|
|
11
|
+
async def main_async():
|
|
12
|
+
print("Starting BibleMate AI Agent...")
|
|
13
|
+
await ai_agent_headless(q=" ".join(args.default))
|
|
14
|
+
print("Finished")
|
|
15
|
+
|
|
16
|
+
def main():
|
|
17
|
+
asyncio.run(main_async())
|
|
18
|
+
|
|
19
|
+
if __name__ == "__main__":
|
|
20
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
biblemateagent
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
biblemateweb>=0.3.56
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import os
|
|
3
|
+
from agentmake import agentmake, DEFAULT_AI_BACKEND, unpack_instruction_content, unpack_system_content
|
|
4
|
+
from agentmake.utils.text_wrapper import get_stream_event_text
|
|
5
|
+
from agentmake.utils.read_assistant_response import is_openai_style
|
|
6
|
+
from biblemateweb import config, DEFAULT_MESSAGES
|
|
7
|
+
|
|
8
|
+
async def stream_response_headless(messages, user_request, cancel_event=None, system=None, **kwargs):
|
|
9
|
+
def get_next_chunk(iterator):
|
|
10
|
+
"""
|
|
11
|
+
Runs in a separate thread.
|
|
12
|
+
Returns the next item, or None if the iterator is exhausted.
|
|
13
|
+
"""
|
|
14
|
+
try:
|
|
15
|
+
return next(iterator)
|
|
16
|
+
except StopIteration:
|
|
17
|
+
return None
|
|
18
|
+
except Exception as e:
|
|
19
|
+
return e # Return the error to be handled in the main loop
|
|
20
|
+
|
|
21
|
+
if "instruction" in kwargs:
|
|
22
|
+
instruction_content = kwargs.pop("instruction")
|
|
23
|
+
instruction_content = unpack_instruction_content(instruction_content)
|
|
24
|
+
# refine user request
|
|
25
|
+
user_request = instruction_content + "\n" + user_request
|
|
26
|
+
|
|
27
|
+
if system == "auto":
|
|
28
|
+
system = await stream_response_headless(DEFAULT_MESSAGES, user_request, cancel_event, system="bible/create_agent", **kwargs)
|
|
29
|
+
if not system or system.strip() == "[NO_CONTENT]":
|
|
30
|
+
return None
|
|
31
|
+
else:
|
|
32
|
+
# refine response
|
|
33
|
+
system = system.replace("should:", "should:\n")
|
|
34
|
+
system = system.replace("examples:", "examples:\n")
|
|
35
|
+
if system.startswith("```agent\n"):
|
|
36
|
+
system = system[9:]
|
|
37
|
+
if system.endswith("```"):
|
|
38
|
+
system = system[:-3].strip()
|
|
39
|
+
elif system is not None:
|
|
40
|
+
system_content = unpack_system_content(system)
|
|
41
|
+
system = None
|
|
42
|
+
# refine user request
|
|
43
|
+
user_request = f"""---
|
|
44
|
+
|
|
45
|
+
START OF YOUR NEW ROLE
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
{system_content}
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
START OF MY REQUEST
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
{user_request}"""
|
|
58
|
+
|
|
59
|
+
# Print loading text
|
|
60
|
+
print("Loading...", end="\r", flush=True)
|
|
61
|
+
await asyncio.sleep(0)
|
|
62
|
+
|
|
63
|
+
backend = kwargs.pop("backend", getattr(config, "ai_backend", "") if getattr(config, "ai_backend", "") else DEFAULT_AI_BACKEND)
|
|
64
|
+
api_key = kwargs.pop("api_key", os.getenv("API_KEY", ""))
|
|
65
|
+
api_endpoint = kwargs.pop("api_endpoint", os.getenv("API_ENDPOINT", ""))
|
|
66
|
+
model = kwargs.pop("model", os.getenv("AI_MODEL", ""))
|
|
67
|
+
max_tokens = kwargs.pop("max_tokens", None)
|
|
68
|
+
temperature = kwargs.pop("temperature", None)
|
|
69
|
+
|
|
70
|
+
disable_local_api_endpoint = getattr(config, "disable_local_api_endpoint", True)
|
|
71
|
+
if disable_local_api_endpoint and (api_endpoint.strip().lower().startswith("http://localhost") or api_endpoint.strip().lower().startswith("http://127.0.0.1")):
|
|
72
|
+
api_endpoint = ""
|
|
73
|
+
|
|
74
|
+
# run completion
|
|
75
|
+
text_chunks = ""
|
|
76
|
+
completion = await asyncio.to_thread(
|
|
77
|
+
agentmake,
|
|
78
|
+
messages,
|
|
79
|
+
system=system,
|
|
80
|
+
backend=backend.strip() if api_key.strip() and not backend.strip() == "default" else config.ai_backend if getattr(config, "ai_backend", "") else DEFAULT_AI_BACKEND,
|
|
81
|
+
model=model.strip() if api_key.strip() and model.strip() and not backend.strip() == "default" else None,
|
|
82
|
+
api_key=api_key.strip() if api_key.strip() and not backend.strip() == "default" else None,
|
|
83
|
+
api_endpoint=api_endpoint.strip() if api_key.strip() and api_endpoint.strip() and not backend.strip() == "default" else None,
|
|
84
|
+
max_tokens=int(max_tokens) if api_key.strip() and max_tokens and not backend.strip() == "default" else None,
|
|
85
|
+
temperature=float(temperature) if api_key.strip() and temperature and not backend.strip() == "default" else None,
|
|
86
|
+
follow_up_prompt=user_request,
|
|
87
|
+
stream=True,
|
|
88
|
+
print_on_terminal=False,
|
|
89
|
+
stream_events_only=True,
|
|
90
|
+
**kwargs,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
print("Running... ", end="\r", flush=True)
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
while cancel_event is None or not cancel_event.is_set():
|
|
97
|
+
event = await asyncio.to_thread(get_next_chunk, completion)
|
|
98
|
+
|
|
99
|
+
if event is None:
|
|
100
|
+
break
|
|
101
|
+
elif isinstance(event, Exception):
|
|
102
|
+
print(f"\nStream interrupted: {str(event)}")
|
|
103
|
+
break
|
|
104
|
+
|
|
105
|
+
actual_backend = backend.strip() if api_key.strip() and not backend.strip() == "default" else config.ai_backend if getattr(config, "ai_backend", "") else DEFAULT_AI_BACKEND
|
|
106
|
+
if text_chunk := get_stream_event_text(event, openai_style=is_openai_style(actual_backend)):
|
|
107
|
+
text_chunks += text_chunk
|
|
108
|
+
print(text_chunk, end="", flush=True)
|
|
109
|
+
await asyncio.sleep(0)
|
|
110
|
+
|
|
111
|
+
if cancel_event is not None and cancel_event.is_set():
|
|
112
|
+
print("\n[Cancelled!]")
|
|
113
|
+
else:
|
|
114
|
+
print() # Print newline when done
|
|
115
|
+
|
|
116
|
+
except Exception as e:
|
|
117
|
+
print(f"\n[Error: {str(e)}]")
|
|
118
|
+
if cancel_event is not None:
|
|
119
|
+
cancel_event.set()
|
|
120
|
+
|
|
121
|
+
if cancel_event is not None and cancel_event.is_set():
|
|
122
|
+
cancel_event = None
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
return text_chunks.replace(" ", " ").replace("‑", "-")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: biblemateagent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: BibleMate AI - Automate Your Bible Study; A headless version of BibleMate AI Agent Mode
|
|
5
|
+
Home-page: https://biblemate.ai
|
|
6
|
+
Author: Eliran Wong
|
|
7
|
+
Author-email: support@marvel.bible
|
|
8
|
+
License: GNU General Public License (GPL)
|
|
9
|
+
Project-URL: Source, https://github.com/eliranwong/biblemateagent
|
|
10
|
+
Project-URL: Tracker, https://github.com/eliranwong/biblemateagent/issues
|
|
11
|
+
Project-URL: Documentation, https://github.com/eliranwong/biblemateagent/wiki
|
|
12
|
+
Project-URL: Funding, https://www.paypal.me/MarvelBible
|
|
13
|
+
Keywords: mcp agent biblemate ai anthropic azure chatgpt cohere deepseek genai github googleai groq llamacpp mistral ollama openai vertexai xai
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: Topic :: Utilities
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
19
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Requires-Python: >=3.10, <3.13
|
|
24
|
+
Requires-Dist: biblemateweb>=0.3.56
|
|
25
|
+
Provides-Extra: genai
|
|
26
|
+
Requires-Dist: google-genai>=1.46.0; extra == "genai"
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: keywords
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: project-url
|
|
35
|
+
Dynamic: provides-extra
|
|
36
|
+
Dynamic: requires-dist
|
|
37
|
+
Dynamic: requires-python
|
|
38
|
+
Dynamic: summary
|
|
39
|
+
|
|
40
|
+
# biblemateagent
|
|
41
|
+
A headless version of BibleMate AI Agent Mode
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
> pip install biblemateagent
|
|
46
|
+
|
|
47
|
+
## Set up data
|
|
48
|
+
|
|
49
|
+
> biblematedata
|
|
50
|
+
|
|
51
|
+
## Run BibleMate Agent
|
|
52
|
+
|
|
53
|
+
> biblemateagent "Your Bible Study Request"
|
|
54
|
+
|
|
55
|
+
or
|
|
56
|
+
|
|
57
|
+
> bibleagent "Your Bible Study Request"
|
|
58
|
+
|
|
59
|
+
## Help
|
|
60
|
+
|
|
61
|
+
> biblemateagent -h
|
|
62
|
+
|
|
63
|
+
or
|
|
64
|
+
|
|
65
|
+
> bibleagent -h
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
biblemateagent/README.md
|
|
4
|
+
biblemateagent/agent.py
|
|
5
|
+
biblemateagent/config.py
|
|
6
|
+
biblemateagent/main.py
|
|
7
|
+
biblemateagent/package_name.txt
|
|
8
|
+
biblemateagent/requirements.txt
|
|
9
|
+
biblemateagent/stream.py
|
|
10
|
+
biblemateagent/version.txt
|
|
11
|
+
biblemateagent.egg-info/PKG-INFO
|
|
12
|
+
biblemateagent.egg-info/SOURCES.txt
|
|
13
|
+
biblemateagent.egg-info/dependency_links.txt
|
|
14
|
+
biblemateagent.egg-info/entry_points.txt
|
|
15
|
+
biblemateagent.egg-info/requires.txt
|
|
16
|
+
biblemateagent.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
biblemateagent
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
from setuptools.command.install import install
|
|
3
|
+
import os, shutil, platform, sys
|
|
4
|
+
|
|
5
|
+
version = "0.1.0"
|
|
6
|
+
with open(os.path.join("biblemateagent", "version.txt"), "w", encoding="utf-8") as fileObj:
|
|
7
|
+
fileObj.write(version)
|
|
8
|
+
|
|
9
|
+
# package name
|
|
10
|
+
package_name_0 = "package_name.txt"
|
|
11
|
+
with open(package_name_0, "r", encoding="utf-8") as fileObj:
|
|
12
|
+
package = fileObj.read()
|
|
13
|
+
package_name_1 = os.path.join(package, "package_name.txt") # package readme
|
|
14
|
+
shutil.copy(package_name_0, package_name_1)
|
|
15
|
+
|
|
16
|
+
# update package readme
|
|
17
|
+
latest_readme = os.path.join("README.md") # github repository readme
|
|
18
|
+
package_readme = os.path.join(package, "README.md") # package readme
|
|
19
|
+
shutil.copy(latest_readme, package_readme)
|
|
20
|
+
with open(package_readme, "r", encoding="utf-8") as fileObj:
|
|
21
|
+
long_description = fileObj.read()
|
|
22
|
+
|
|
23
|
+
# get required packages
|
|
24
|
+
install_requires = []
|
|
25
|
+
with open(os.path.join(package, "requirements.txt"), "r") as fileObj:
|
|
26
|
+
for line in fileObj.readlines():
|
|
27
|
+
mod = line.strip()
|
|
28
|
+
if mod:
|
|
29
|
+
install_requires.append(mod)
|
|
30
|
+
|
|
31
|
+
# make sure config.py is empty
|
|
32
|
+
open(os.path.join(package, "config.py"), "w").close()
|
|
33
|
+
|
|
34
|
+
# https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/
|
|
35
|
+
setup(
|
|
36
|
+
name=package,
|
|
37
|
+
version=version,
|
|
38
|
+
python_requires=">=3.10, <3.13",
|
|
39
|
+
description=f"BibleMate AI - Automate Your Bible Study; A headless version of BibleMate AI Agent Mode",
|
|
40
|
+
long_description=long_description,
|
|
41
|
+
author="Eliran Wong",
|
|
42
|
+
author_email="support@marvel.bible",
|
|
43
|
+
packages=[
|
|
44
|
+
package,
|
|
45
|
+
],
|
|
46
|
+
package_data={
|
|
47
|
+
package: ["*.*"],
|
|
48
|
+
},
|
|
49
|
+
license="GNU General Public License (GPL)",
|
|
50
|
+
install_requires=install_requires,
|
|
51
|
+
extras_require={
|
|
52
|
+
'genai': ["google-genai>=1.46.0"], # Dependencies for running Vertex AI
|
|
53
|
+
},
|
|
54
|
+
entry_points={
|
|
55
|
+
"console_scripts": [
|
|
56
|
+
f"bmagent={package}.main:main",
|
|
57
|
+
f"biblemateagent={package}.main:main",
|
|
58
|
+
f"bibleagent={package}.main:main",
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
keywords="mcp agent biblemate ai anthropic azure chatgpt cohere deepseek genai github googleai groq llamacpp mistral ollama openai vertexai xai",
|
|
62
|
+
url="https://biblemate.ai",
|
|
63
|
+
project_urls={
|
|
64
|
+
"Source": "https://github.com/eliranwong/biblemateagent",
|
|
65
|
+
"Tracker": "https://github.com/eliranwong/biblemateagent/issues",
|
|
66
|
+
"Documentation": "https://github.com/eliranwong/biblemateagent/wiki",
|
|
67
|
+
"Funding": "https://www.paypal.me/MarvelBible",
|
|
68
|
+
},
|
|
69
|
+
classifiers=[
|
|
70
|
+
# Reference: https://pypi.org/classifiers/
|
|
71
|
+
|
|
72
|
+
# How mature is this project? Common values are
|
|
73
|
+
# 3 - Alpha
|
|
74
|
+
# 4 - Beta
|
|
75
|
+
# 5 - Production/Stable
|
|
76
|
+
'Development Status :: 5 - Production/Stable',
|
|
77
|
+
|
|
78
|
+
# Indicate who your project is intended for
|
|
79
|
+
'Intended Audience :: End Users/Desktop',
|
|
80
|
+
'Topic :: Utilities',
|
|
81
|
+
'Topic :: Scientific/Engineering :: Artificial Intelligence',
|
|
82
|
+
'Topic :: Software Development :: Build Tools',
|
|
83
|
+
|
|
84
|
+
# Pick your license as you wish (should match "license" above)
|
|
85
|
+
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
|
|
86
|
+
|
|
87
|
+
# Specify the Python versions you support here. In particular, ensure
|
|
88
|
+
# that you indicate whether you support Python 2, Python 3 or both.
|
|
89
|
+
#'Programming Language :: Python :: 3.8',
|
|
90
|
+
#'Programming Language :: Python :: 3.9',
|
|
91
|
+
# currently, fastmcp supports 3.10-3.12
|
|
92
|
+
'Programming Language :: Python :: 3.10',
|
|
93
|
+
'Programming Language :: Python :: 3.11',
|
|
94
|
+
'Programming Language :: Python :: 3.12',
|
|
95
|
+
],
|
|
96
|
+
)
|