vibesurf 0.1.23__tar.gz → 0.1.24__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.

Potentially problematic release.


This version of vibesurf might be problematic. Click here for more details.

Files changed (124) hide show
  1. {vibesurf-0.1.23 → vibesurf-0.1.24}/PKG-INFO +2 -1
  2. {vibesurf-0.1.23 → vibesurf-0.1.24}/pyproject.toml +1 -0
  3. {vibesurf-0.1.23 → vibesurf-0.1.24}/tests/test_agents.py +51 -44
  4. {vibesurf-0.1.23 → vibesurf-0.1.24}/tests/test_tools.py +12 -1
  5. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/_version.py +3 -3
  6. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/agents/vibe_surf_agent.py +1 -1
  7. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/config.py +3 -1
  8. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/utils/llm_factory.py +2 -1
  9. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/llm/openai_compatible.py +35 -10
  10. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/file_system.py +2 -2
  11. vibesurf-0.1.24/vibe_surf/tools/finance_tools.py +586 -0
  12. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/report_writer_tools.py +2 -1
  13. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/vibesurf_tools.py +91 -2
  14. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/views.py +33 -0
  15. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibesurf.egg-info/PKG-INFO +2 -1
  16. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibesurf.egg-info/SOURCES.txt +2 -0
  17. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibesurf.egg-info/requires.txt +1 -0
  18. {vibesurf-0.1.23 → vibesurf-0.1.24}/.env.example +0 -0
  19. {vibesurf-0.1.23 → vibesurf-0.1.24}/.github/workflows/publish.yml +0 -0
  20. {vibesurf-0.1.23 → vibesurf-0.1.24}/.gitignore +0 -0
  21. {vibesurf-0.1.23 → vibesurf-0.1.24}/.python-version +0 -0
  22. {vibesurf-0.1.23 → vibesurf-0.1.24}/LICENSE +0 -0
  23. {vibesurf-0.1.23 → vibesurf-0.1.24}/MANIFEST.in +0 -0
  24. {vibesurf-0.1.23 → vibesurf-0.1.24}/README.md +0 -0
  25. {vibesurf-0.1.23 → vibesurf-0.1.24}/docs/EXECUTABLE_BUILD.md +0 -0
  26. {vibesurf-0.1.23 → vibesurf-0.1.24}/docs/PYPI_SETUP.md +0 -0
  27. {vibesurf-0.1.23 → vibesurf-0.1.24}/scripts/build-local.bat +0 -0
  28. {vibesurf-0.1.23 → vibesurf-0.1.24}/scripts/build-local.sh +0 -0
  29. {vibesurf-0.1.23 → vibesurf-0.1.24}/setup.cfg +0 -0
  30. {vibesurf-0.1.23 → vibesurf-0.1.24}/tests/test_backend_api.py +0 -0
  31. {vibesurf-0.1.23 → vibesurf-0.1.24}/tests/test_browser.py +0 -0
  32. {vibesurf-0.1.23 → vibesurf-0.1.24}/tests/test_voice_api.py +0 -0
  33. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/__init__.py +0 -0
  34. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/agents/__init__.py +0 -0
  35. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/agents/browser_use_agent.py +0 -0
  36. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/agents/prompts/__init__.py +0 -0
  37. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/agents/prompts/report_writer_prompt.py +0 -0
  38. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/agents/prompts/vibe_surf_prompt.py +0 -0
  39. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/agents/report_writer_agent.py +0 -0
  40. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/agents/views.py +0 -0
  41. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/__init__.py +0 -0
  42. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/__init__.py +0 -0
  43. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/activity.py +0 -0
  44. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/agent.py +0 -0
  45. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/browser.py +0 -0
  46. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/files.py +0 -0
  47. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/models.py +0 -0
  48. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/task.py +0 -0
  49. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/api/voices.py +0 -0
  50. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/__init__.py +0 -0
  51. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/manager.py +0 -0
  52. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/migrations/v001_initial_schema.sql +0 -0
  53. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/migrations/v002_add_agent_mode.sql +0 -0
  54. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/migrations/v003_fix_task_status_case.sql +0 -0
  55. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/migrations/v004_add_voice_profiles.sql +0 -0
  56. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/models.py +0 -0
  57. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/queries.py +0 -0
  58. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/database/schemas.py +0 -0
  59. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/llm_config.py +0 -0
  60. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/main.py +0 -0
  61. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/shared_state.py +0 -0
  62. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/utils/__init__.py +0 -0
  63. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/utils/encryption.py +0 -0
  64. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/backend/voice_model_config.py +0 -0
  65. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/browser/__init__.py +0 -0
  66. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/browser/agen_browser_profile.py +0 -0
  67. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/browser/agent_browser_session.py +0 -0
  68. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/browser/browser_manager.py +0 -0
  69. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/browser/utils.py +0 -0
  70. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/browser/watchdogs/__init__.py +0 -0
  71. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/browser/watchdogs/action_watchdog.py +0 -0
  72. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/browser/watchdogs/dom_watchdog.py +0 -0
  73. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/background.js +0 -0
  74. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/config.js +0 -0
  75. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/content.js +0 -0
  76. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/dev-reload.js +0 -0
  77. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/icons/logo.icns +0 -0
  78. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/icons/logo.png +0 -0
  79. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/manifest.json +0 -0
  80. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/permission-iframe.html +0 -0
  81. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/permission-request.html +0 -0
  82. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/popup.html +0 -0
  83. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/api-client.js +0 -0
  84. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/file-manager.js +0 -0
  85. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/history-manager.js +0 -0
  86. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/main.js +0 -0
  87. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/markdown-it.min.js +0 -0
  88. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/modal-manager.js +0 -0
  89. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/permission-iframe-request.js +0 -0
  90. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/permission-request.js +0 -0
  91. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/session-manager.js +0 -0
  92. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/settings-manager.js +0 -0
  93. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/ui-manager.js +0 -0
  94. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/user-settings-storage.js +0 -0
  95. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/scripts/voice-recorder.js +0 -0
  96. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/sidepanel.html +0 -0
  97. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/activity.css +0 -0
  98. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/animations.css +0 -0
  99. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/base.css +0 -0
  100. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/components.css +0 -0
  101. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/history-modal.css +0 -0
  102. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/input.css +0 -0
  103. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/layout.css +0 -0
  104. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/responsive.css +0 -0
  105. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/settings-environment.css +0 -0
  106. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/settings-forms.css +0 -0
  107. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/settings-modal.css +0 -0
  108. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/settings-profiles.css +0 -0
  109. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/settings-responsive.css +0 -0
  110. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/settings-utilities.css +0 -0
  111. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/chrome_extension/styles/variables.css +0 -0
  112. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/cli.py +0 -0
  113. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/common.py +0 -0
  114. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/llm/__init__.py +0 -0
  115. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/logger.py +0 -0
  116. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/__init__.py +0 -0
  117. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/browser_use_tools.py +0 -0
  118. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/mcp_client.py +0 -0
  119. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/vibesurf_registry.py +0 -0
  120. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibe_surf/tools/voice_asr.py +0 -0
  121. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibesurf.egg-info/dependency_links.txt +0 -0
  122. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibesurf.egg-info/entry_points.txt +0 -0
  123. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibesurf.egg-info/top_level.txt +0 -0
  124. {vibesurf-0.1.23 → vibesurf-0.1.24}/vibesurf.spec +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vibesurf
3
- Version: 0.1.23
3
+ Version: 0.1.24
4
4
  Summary: VibeSurf: A powerful browser assistant for vibe surfing
5
5
  Author: Shao Warm
6
6
  License: Apache-2.0
@@ -43,6 +43,7 @@ Requires-Dist: nanoid>=2.0.0
43
43
  Requires-Dist: markdownify>=1.2.0
44
44
  Requires-Dist: pathvalidate>=3.3.1
45
45
  Requires-Dist: dashscope>=1.24.5
46
+ Requires-Dist: yfinance>=0.2.66
46
47
  Dynamic: license-file
47
48
 
48
49
  # VibeSurf: A powerful browser assistant for vibe surfing
@@ -44,6 +44,7 @@ dependencies = [
44
44
  "markdownify>=1.2.0",
45
45
  "pathvalidate>=3.3.1",
46
46
  "dashscope>=1.24.5",
47
+ "yfinance>=0.2.66",
47
48
  ]
48
49
 
49
50
  [project.urls]
@@ -18,9 +18,11 @@ from vibe_surf.browser.agen_browser_profile import AgentBrowserProfile
18
18
  from vibe_surf.tools.browser_use_tools import BrowserUseTools
19
19
  from vibe_surf.tools.vibesurf_tools import VibeSurfTools
20
20
  from vibe_surf.llm.openai_compatible import ChatOpenAICompatible
21
+ from browser_use.llm.deepseek.chat import ChatDeepSeek
21
22
  from vibe_surf.agents.browser_use_agent import BrowserUseAgent
22
23
  from vibe_surf.agents.vibe_surf_agent import VibeSurfAgent
23
24
 
25
+
24
26
  async def run_single_bu_agent():
25
27
  import platform
26
28
  if platform.system() != "Darwin":
@@ -46,9 +48,13 @@ async def run_single_bu_agent():
46
48
  # base_url=os.getenv("ALIBABA_ENDPOINT"),
47
49
  # api_key=os.getenv("ALIBABA_API_KEY"))
48
50
 
49
- llm = ChatOpenAICompatible(model='kimi-k2-turbo-preview',
50
- base_url=os.getenv("MOONSHOT_ENDPOINT"),
51
- api_key=os.getenv("MOONSHOT_API_KEY"))
51
+ # llm = ChatOpenAICompatible(model='kimi-k2-turbo-preview',
52
+ # base_url=os.getenv("MOONSHOT_ENDPOINT"),
53
+ # api_key=os.getenv("MOONSHOT_API_KEY"))
54
+
55
+ llm = ChatOpenAICompatible(model='deepseek-reasoner',
56
+ base_url=os.getenv("DEEPSEEK_ENDPOINT"),
57
+ api_key=os.getenv("DEEPSEEK_API_KEY"))
52
58
 
53
59
  task = "Search Google for 'Elon Mask' and tell me the top 3 results"
54
60
 
@@ -159,20 +165,22 @@ async def test_vibe_surf_agent():
159
165
  await main_browser_session.start()
160
166
  vs_tools = VibeSurfTools()
161
167
  browser_manager = BrowserManager(main_browser_session=main_browser_session)
162
- llm = ChatOpenAICompatible(model='gemini-2.5-flash',
163
- base_url=os.getenv("OPENAI_ENDPOINT"),
164
- api_key=os.getenv("OPENAI_API_KEY"))
168
+ # llm = ChatOpenAICompatible(model='gemini-2.5-flash',
169
+ # base_url=os.getenv("OPENAI_ENDPOINT"),
170
+ # api_key=os.getenv("OPENAI_API_KEY"))
171
+
172
+ llm = ChatOpenAICompatible(model='deepseek-chat',
173
+ base_url=os.getenv("DEEPSEEK_ENDPOINT"),
174
+ api_key=os.getenv("DEEPSEEK_API_KEY"))
165
175
 
166
-
167
176
  # Create VibeSurfAgent
168
177
  agent = VibeSurfAgent(
169
178
  llm=llm,
170
179
  browser_manager=browser_manager,
171
180
  tools=vs_tools,
172
- workspace_dir=os.path.abspath("./tmp/vibesurf_tests"),
173
- calculate_token_cost=True
181
+ workspace_dir=os.path.abspath("./tmp/vibesurf_tests")
174
182
  )
175
-
183
+
176
184
  try:
177
185
  # Test 1: Simple task (should not require browser)
178
186
  print("🧪 Testing simple task...")
@@ -200,16 +208,16 @@ async def test_vibe_surf_agent():
200
208
  # print("🎉 All VibeSurfAgent tests passed!")
201
209
 
202
210
  # Test 4: Browser parallel task
203
- print("🧪 Testing browser parallel tasks...")
204
- browser_task = "Search for Dify, n8n, browser-use and click into their own homepage, take screenshot and save"
205
- result4 = await agent.run(browser_task)
206
- print(f"✅ Browser task result:")
207
- pprint.pprint(result4)
208
- with open("./tmp/vibesurf_tests/parallel_test.md", "w", encoding='utf-8') as fw:
209
- fw.write(result4)
210
- assert result4 is not None and len(result4) > 0
211
+ # print("🧪 Testing browser parallel tasks...")
212
+ # browser_task = "Search for Dify, n8n, browser-use and click into their own homepage, take screenshot and save"
213
+ # result4 = await agent.run(browser_task)
214
+ # print(f"✅ Browser task result:")
215
+ # pprint.pprint(result4)
216
+ # with open("./tmp/vibesurf_tests/parallel_test.md", "w", encoding='utf-8') as fw:
217
+ # fw.write(result4)
218
+ # assert result4 is not None and len(result4) > 0
211
219
  print("🎉 All VibeSurfAgent tests passed!")
212
-
220
+
213
221
  except Exception as e:
214
222
  print(f"❌ VibeSurfAgent test failed: {e}")
215
223
  raise e
@@ -240,7 +248,6 @@ async def test_vibe_surf_agent_control():
240
248
  llm = ChatOpenAICompatible(model='gemini-2.5-pro',
241
249
  base_url=os.getenv("OPENAI_ENDPOINT"),
242
250
  api_key=os.getenv("OPENAI_API_KEY"))
243
-
244
251
 
245
252
  # Create VibeSurfAgent
246
253
  agent = VibeSurfAgent(
@@ -253,69 +260,69 @@ async def test_vibe_surf_agent_control():
253
260
 
254
261
  try:
255
262
  print("🧪 Testing VibeSurfAgent control functionality...")
256
-
263
+
257
264
  # Test 1: Status check when idle
258
265
  print("📊 Testing initial status...")
259
266
  status = agent.get_status()
260
267
  print(f"Initial status: {status.overall_status}")
261
268
  assert status.overall_status == "idle"
262
-
269
+
263
270
  # Test 2: Start a long-running browser task
264
271
  print("🚀 Starting long-running browser task...")
265
272
  browser_task = "Search for Dify, n8n, langflow and gather relative information, and generate a detailed report for comparison"
266
-
273
+
267
274
  # Start task in background
268
275
  async def run_task():
269
276
  return await agent.run(browser_task)
270
-
277
+
271
278
  task_coroutine = asyncio.create_task(run_task())
272
-
279
+
273
280
  # Wait a bit for task to start
274
281
  await asyncio.sleep(10)
275
-
282
+
276
283
  # Test 3: Check status during execution
277
284
  print("📊 Checking status during execution...")
278
285
  status = agent.get_status()
279
286
  print(f"Running status: {status.overall_status}")
280
287
  print(f"Progress: {status.progress}")
281
288
  print(f"Active agents: {len(status.agent_statuses)}")
282
-
289
+
283
290
  # Test 4: Pause execution
284
291
  print("⏸️ Testing pause functionality...")
285
292
  pause_result = await agent.pause("Testing pause functionality")
286
293
  print(f"Pause result: {pause_result.success} - {pause_result.message}")
287
294
  assert pause_result.success
288
-
295
+
289
296
  # Check status after pause
290
297
  await asyncio.sleep(1)
291
298
  status = agent.get_status()
292
299
  print(f"Paused status: {status.overall_status}")
293
300
  assert status.overall_status == "paused"
294
-
301
+
295
302
  # Test 5: Resume execution
296
303
  print("▶️ Testing resume functionality...")
297
304
  resume_result = await agent.resume("Testing resume functionality")
298
305
  print(f"Resume result: {resume_result.success} - {resume_result.message}")
299
306
  assert resume_result.success
300
-
307
+
301
308
  # Check status after resume
302
309
  await asyncio.sleep(1)
303
310
  status = agent.get_status()
304
311
  print(f"Resumed status: {status.overall_status}")
305
-
312
+
306
313
  # Let it run a bit more
307
314
  await asyncio.sleep(50)
308
-
315
+
309
316
  # Test 6: Stop execution
310
317
  print("🛑 Testing stop functionality...")
311
318
  stop_result = await agent.stop("Testing stop functionality")
312
319
  print(f"Stop result: {stop_result.success} - {stop_result.message}")
313
-
320
+
314
321
  # Check status after stop (should be stopped even if stop had issues)
315
322
  await asyncio.sleep(1)
316
323
  status = agent.get_status()
317
324
  print(f"Stopped status: {status.overall_status}")
318
-
325
+
319
326
  # Wait for task to complete (it should be cancelled)
320
327
  try:
321
328
  result = await asyncio.wait_for(task_coroutine, timeout=3)
@@ -329,38 +336,38 @@ async def test_vibe_surf_agent_control():
329
336
  pass
330
337
  except asyncio.CancelledError:
331
338
  print("✅ Task was cancelled as expected")
332
-
339
+
333
340
  # Verify stop worked (may have timed out but should still be effective)
334
341
  if stop_result.success:
335
342
  assert status.overall_status == "idle"
336
343
  else:
337
344
  print(f"⚠️ Stop operation had issues but continuing: {stop_result.message}")
338
-
345
+
339
346
  # Test 7: Test simple task control (should work quickly)
340
347
  print("🔄 Testing control on simple task...")
341
348
  simple_task = "Find out who is the founder of Browser-Use."
342
-
349
+
343
350
  async def run_simple_task():
344
351
  return await agent.run(simple_task)
345
-
352
+
346
353
  simple_task_coroutine = asyncio.create_task(run_simple_task())
347
-
354
+
348
355
  # Pause quickly
349
356
  await asyncio.sleep(0.5)
350
357
  pause_result = await agent.pause("Testing simple task pause")
351
358
  print(f"Simple task pause: {pause_result.success}")
352
-
359
+
353
360
  # Resume
354
361
  await asyncio.sleep(0.5)
355
362
  resume_result = await agent.resume("Testing simple task resume")
356
363
  print(f"Simple task resume: {resume_result.success}")
357
-
364
+
358
365
  # Let it complete
359
366
  simple_result = await simple_task_coroutine
360
367
  print(f"Simple task completed: {len(simple_result) > 0}")
361
368
  print(simple_result)
362
369
  print("🎉 All VibeSurfAgent control tests passed!")
363
-
370
+
364
371
  except Exception as e:
365
372
  print(f"❌ VibeSurfAgent control test failed: {e}")
366
373
  import traceback
@@ -377,7 +384,7 @@ async def test_vibe_surf_agent_control():
377
384
 
378
385
 
379
386
  if __name__ == "__main__":
380
- asyncio.run(run_single_bu_agent())
387
+ # asyncio.run(run_single_bu_agent())
381
388
  # asyncio.run(run_multi_bu_agents())
382
- # asyncio.run(test_vibe_surf_agent())
389
+ asyncio.run(test_vibe_surf_agent())
383
390
  # asyncio.run(test_vibe_surf_agent_control())
@@ -116,8 +116,19 @@ async def test_vibesurf_tools():
116
116
  print(tools.registry.registry.actions.keys())
117
117
 
118
118
 
119
+ async def test_finance_tools():
120
+ from vibe_surf.tools.finance_tools import FinanceDataRetriever
121
+
122
+ retriever = FinanceDataRetriever('TSLA')
123
+
124
+ result = retriever.get_finance_data(["get_news"])
125
+
126
+ pdb.set_trace()
127
+
128
+
119
129
  if __name__ == '__main__':
120
130
  # asyncio.run(test_tools_with_mcp())
121
131
  # asyncio.run(test_filesystem())
122
132
  # asyncio.run(test_bu_tools())
123
- asyncio.run(test_vibesurf_tools())
133
+ # asyncio.run(test_vibesurf_tools())
134
+ asyncio.run(test_finance_tools())
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.1.23'
32
- __version_tuple__ = version_tuple = (0, 1, 23)
31
+ __version__ = version = '0.1.24'
32
+ __version_tuple__ = version_tuple = (0, 1, 24)
33
33
 
34
- __commit_id__ = commit_id = 'g415c8bc4e'
34
+ __commit_id__ = commit_id = 'gebf62a182'
@@ -479,7 +479,7 @@ async def _vibesurf_agent_node_impl(state: VibeSurfState) -> VibeSurfState:
479
479
  llm=vibesurf_agent.llm,
480
480
  file_system=vibesurf_agent.file_system,
481
481
  )
482
- if "skill_search" in action_name or "skill_crawl" in action_name or "skill_summary" in action_name:
482
+ if action_name in ["skill_search", "skill_crawl", "skill_summary", "skill_finance"]:
483
483
  state.current_step = "END"
484
484
  # Format final response
485
485
  final_response = f"{result.extracted_content}"
@@ -234,7 +234,9 @@ async def update_llm_profile(
234
234
 
235
235
  # Return updated profile
236
236
  updated_profile = await LLMProfileQueries.get_profile(db, profile_name)
237
-
237
+ from ..shared_state import current_llm_profile_name
238
+ if current_llm_profile_name != profile_name:
239
+ current_llm_profile_name = None
238
240
  # Use safe extraction to avoid greenlet issues
239
241
  return LLMProfileResponse(**_profile_to_response_dict(updated_profile))
240
242
 
@@ -142,8 +142,9 @@ def create_llm_from_profile(llm_profile) -> BaseChatModel:
142
142
  )
143
143
 
144
144
  elif provider == "deepseek":
145
- return ChatDeepSeek(
145
+ return ChatOpenAICompatible(
146
146
  model=model,
147
+ base_url="https://api.deepseek.com",
147
148
  api_key=api_key,
148
149
  **common_params
149
150
  )
@@ -51,6 +51,8 @@ from browser_use.llm.openai.serializer import OpenAIMessageSerializer
51
51
  from browser_use.llm.schema import SchemaOptimizer
52
52
  from browser_use.llm.views import ChatInvokeCompletion, ChatInvokeUsage
53
53
 
54
+ from json_repair import repair_json
55
+
54
56
  T = TypeVar('T', bound=BaseModel)
55
57
 
56
58
  from vibe_surf.logger import get_logger
@@ -74,6 +76,8 @@ class ChatOpenAICompatible(ChatOpenAI):
74
76
  The class automatically detects the model type and applies appropriate fixes.
75
77
  """
76
78
 
79
+ max_completion_tokens: int | None = 16000
80
+
77
81
  def _is_gemini_model(self) -> bool:
78
82
  """Check if the current model is a Gemini model."""
79
83
  return str(self.model).lower().startswith('gemini')
@@ -82,6 +86,11 @@ class ChatOpenAICompatible(ChatOpenAI):
82
86
  """Check if the current model is a Kimi/Moonshot model."""
83
87
  model_str = str(self.model).lower()
84
88
  return 'kimi' in model_str or 'moonshot' in model_str
89
+
90
+ def _is_deepseek_model(self) -> bool:
91
+ """Check if the current model is a Kimi/Moonshot model."""
92
+ model_str = str(self.model).lower()
93
+ return 'deepseek' in model_str
85
94
 
86
95
  def _is_qwen_model(self) -> bool:
87
96
  """Check if the current model is a Qwen model."""
@@ -223,10 +232,10 @@ class ChatOpenAICompatible(ChatOpenAI):
223
232
  """
224
233
  # If this is not a special model or no structured output is requested,
225
234
  # use the parent implementation directly
226
- if self._is_qwen_model() or self._is_kimi_model():
235
+ if self._is_qwen_model() or self._is_kimi_model() or self._is_deepseek_model() :
227
236
  self.add_schema_to_system_prompt = True
228
237
 
229
- if not (self._is_gemini_model() or self._is_kimi_model() or self._is_qwen_model()) or output_format is None:
238
+ if not (self._is_gemini_model() or self._is_kimi_model() or self._is_qwen_model() or self._is_deepseek_model()) or output_format is None:
230
239
  return await super().ainvoke(messages, output_format)
231
240
  openai_messages = OpenAIMessageSerializer.serialize_messages(messages)
232
241
 
@@ -241,6 +250,7 @@ class ChatOpenAICompatible(ChatOpenAI):
241
250
 
242
251
  if self.max_completion_tokens is not None:
243
252
  model_params['max_completion_tokens'] = self.max_completion_tokens
253
+ model_params['max_tokens'] = self.max_completion_tokens
244
254
 
245
255
  if self.top_p is not None:
246
256
  model_params['top_p'] = self.top_p
@@ -298,12 +308,22 @@ class ChatOpenAICompatible(ChatOpenAI):
298
308
  ]
299
309
 
300
310
  # Return structured response
301
- response = await self.get_client().chat.completions.create(
302
- model=self.model,
303
- messages=openai_messages,
304
- response_format=ResponseFormatJSONSchema(json_schema=response_format, type='json_schema'),
305
- **model_params,
306
- )
311
+ if self.add_schema_to_system_prompt:
312
+ response = await self.get_client().chat.completions.create(
313
+ model=self.model,
314
+ messages=openai_messages,
315
+ response_format={
316
+ 'type': 'json_object'
317
+ },
318
+ **model_params,
319
+ )
320
+ else:
321
+ response = await self.get_client().chat.completions.create(
322
+ model=self.model,
323
+ messages=openai_messages,
324
+ response_format=ResponseFormatJSONSchema(json_schema=response_format, type='json_schema'),
325
+ **model_params,
326
+ )
307
327
 
308
328
  if response.choices[0].message.content is None:
309
329
  raise ModelProviderError(
@@ -313,8 +333,13 @@ class ChatOpenAICompatible(ChatOpenAI):
313
333
  )
314
334
 
315
335
  usage = self._get_usage(response)
316
-
317
- parsed = output_format.model_validate_json(response.choices[0].message.content)
336
+ output_content = response.choices[0].message.content
337
+ try:
338
+ parsed = output_format.model_validate_json(output_content)
339
+ except Exception as e:
340
+ pdb.set_trace()
341
+ repair_content = repair_json(output_content)
342
+ parsed = output_format.model_validate_json(repair_content)
318
343
 
319
344
  return ChatInvokeCompletion(
320
345
  completion=parsed,
@@ -224,9 +224,9 @@ class CustomFileSystem(FileSystem):
224
224
  def _is_valid_filename(self, file_name: str) -> bool:
225
225
  """Check if filename matches the required pattern: name.extension"""
226
226
  # Build extensions pattern from _file_types
227
- file_name = os.path.basename(file_name)
227
+ file_name = os.path.splitext(file_name)[1]
228
228
  extensions = '|'.join(self._file_types.keys())
229
- pattern = rf'^[a-zA-Z0-9_\-]+\.({extensions})$'
229
+ pattern = rf'\.({extensions})$'
230
230
  return bool(re.match(pattern, file_name))
231
231
 
232
232
  async def append_file(self, full_filename: str, content: str) -> str: