mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-15 02:06:03 +00:00
Compare commits
2 Commits
codex/surv
...
codex/spac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77a6c24e16 | ||
|
|
9a04bfc364 |
@@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
@@ -84,8 +85,17 @@ class ModelManager:
|
|||||||
self.ap.logger.info('LangBot Space Models service is disabled, skipping sync.')
|
self.ap.logger.info('LangBot Space Models service is disabled, skipping sync.')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
sync_timeout = space_config.get('models_sync_timeout')
|
||||||
try:
|
try:
|
||||||
|
if sync_timeout:
|
||||||
|
await asyncio.wait_for(
|
||||||
|
self.sync_new_models_from_space(),
|
||||||
|
timeout=float(sync_timeout),
|
||||||
|
)
|
||||||
|
else:
|
||||||
await self.sync_new_models_from_space()
|
await self.sync_new_models_from_space()
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
self.ap.logger.warning(f'LangBot Space model sync timed out after {sync_timeout}s, skipping startup sync.')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.ap.logger.warning('Failed to sync new models from LangBot Space, model list may not be updated.')
|
self.ap.logger.warning('Failed to sync new models from LangBot Space, model list may not be updated.')
|
||||||
self.ap.logger.warning(f' - Error: {e}')
|
self.ap.logger.warning(f' - Error: {e}')
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from unittest.mock import AsyncMock, Mock
|
from unittest.mock import AsyncMock, Mock
|
||||||
|
|
||||||
@@ -88,6 +89,28 @@ def test_token_manager_next_token_ignores_empty_token_list():
|
|||||||
assert token_mgr.using_token_index == 0
|
assert token_mgr.using_token_index == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_model_manager_initialize_skips_space_sync_after_timeout():
|
||||||
|
ap = SimpleNamespace()
|
||||||
|
ap.discover = SimpleNamespace(get_components_by_kind=Mock(return_value=[]))
|
||||||
|
ap.instance_config = SimpleNamespace(data={'space': {'models_sync_timeout': 0.01}})
|
||||||
|
ap.logger = Mock()
|
||||||
|
|
||||||
|
mgr = ModelManager(ap)
|
||||||
|
mgr.load_models_from_db = AsyncMock()
|
||||||
|
|
||||||
|
async def slow_sync():
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
mgr.sync_new_models_from_space = AsyncMock(side_effect=slow_sync)
|
||||||
|
|
||||||
|
await mgr.initialize()
|
||||||
|
|
||||||
|
mgr.load_models_from_db.assert_awaited_once()
|
||||||
|
mgr.sync_new_models_from_space.assert_awaited_once()
|
||||||
|
ap.logger.warning.assert_any_call('LangBot Space model sync timed out after 0.01s, skipping startup sync.')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_updated_llm_model_is_immediately_usable_by_local_agent_pipeline():
|
async def test_updated_llm_model_is_immediately_usable_by_local_agent_pipeline():
|
||||||
from langbot.pkg.api.http.service.model import LLMModelsService
|
from langbot.pkg.api.http.service.model import LLMModelsService
|
||||||
|
|||||||
@@ -310,7 +310,6 @@ function SingleSelectField({
|
|||||||
{options.map((opt) => (
|
{options.map((opt) => (
|
||||||
<div key={opt.id}>
|
<div key={opt.id}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
|
||||||
onClick={() => onChange(opt.id)}
|
onClick={() => onChange(opt.id)}
|
||||||
className={`w-full text-left text-sm px-3 py-2 rounded-lg border transition-colors ${
|
className={`w-full text-left text-sm px-3 py-2 rounded-lg border transition-colors ${
|
||||||
value === opt.id
|
value === opt.id
|
||||||
@@ -362,16 +361,8 @@ function MultiSelectField({
|
|||||||
const selected = value.includes(opt.id);
|
const selected = value.includes(opt.id);
|
||||||
return (
|
return (
|
||||||
<div key={opt.id}>
|
<div key={opt.id}>
|
||||||
<div
|
<button
|
||||||
role="button"
|
|
||||||
tabIndex={0}
|
|
||||||
onClick={() => toggle(opt.id)}
|
onClick={() => toggle(opt.id)}
|
||||||
onKeyDown={(e) => {
|
|
||||||
if (e.key === 'Enter' || e.key === ' ') {
|
|
||||||
e.preventDefault();
|
|
||||||
toggle(opt.id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className={`w-full text-left text-sm px-3 py-2 rounded-lg border transition-colors flex items-center gap-2 ${
|
className={`w-full text-left text-sm px-3 py-2 rounded-lg border transition-colors flex items-center gap-2 ${
|
||||||
selected
|
selected
|
||||||
? 'border-primary bg-primary/5 text-primary'
|
? 'border-primary bg-primary/5 text-primary'
|
||||||
@@ -380,7 +371,7 @@ function MultiSelectField({
|
|||||||
>
|
>
|
||||||
<Checkbox checked={selected} className="pointer-events-none" />
|
<Checkbox checked={selected} className="pointer-events-none" />
|
||||||
{getI18nText(opt.label)}
|
{getI18nText(opt.label)}
|
||||||
</div>
|
</button>
|
||||||
{opt.has_input && selected && (
|
{opt.has_input && selected && (
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
Reference in New Issue
Block a user