mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-24 01:15:24 +08:00
* fix(space): keep dedicated-environment Space login working
A dedicated environment runs the OSS runtime with system.edition=cloud. The
process-level 'LangBot Models' compatibility provider is part of the OSS
single-Workspace contract, but write_space_model_providers() skipped creating it
for every non-community edition. The Space OAuth callback then unconditionally
rewarded the provider row by api key, so provider_service raised
WorkspaceNotFoundError('Provider not found') and the whole callback returned 404
-- after the Account and its Workspace had already been created. Every retry
failed the same way, making dedicated-environment login impossible on 4.11.x.
Gate the compatibility provider on the deployment shape instead of the edition
(genuine multi-tenant Cloud runs in CLOUD_RUNTIME persistence and never reaches
this path), and treat a missing provider row as a model-routing warning rather
than an authentication failure so a data anomaly can never block login.
* fix(agent): bind the first model to the 4.11 runner config
create_llm_model() still wrote the auto-selected model into the pre-4.11
ai['local-agent'] container. On a 4.11 Workspace that key does not exist, so the
assignment raised KeyError and POST /provider/models/llm returned 500 the first
time a user added a model -- and the default pipeline kept primary='', so every
Agent run failed with 'No authorized model for local-agent'.
Delegate to RunnerDefaultConfigService, which resolves the selected runner and
writes the schema-defined model selector into ai.runner_config[<runner id>].
Also default the NOT NULL description column on pipeline and bot creation:
omitting an optional description returned a 500 from the constraint instead of
creating the resource.
* fix(agent): keep seeding the model for pipelines that never migrated
set_pipeline_llm_model_if_empty() returns False when a pipeline has no 4.11
runner selected -- that is exactly the un-migrated shape, which still carries
ai.local-agent. Seed that container, but only when it exists, so the legacy path
keeps its old behaviour without the KeyError.
57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
import types
|
|
|
|
import pytest
|
|
|
|
from langbot.pkg.api.http.service.pipeline import PipelineService
|
|
|
|
|
|
async def _noop(*args, **kwargs):
|
|
return None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_pipeline_defaults_missing_description(monkeypatch):
|
|
"""legacy_pipelines.description is NOT NULL; omitting it must not 500."""
|
|
captured = {}
|
|
|
|
app = types.SimpleNamespace()
|
|
app.persistence_mgr = types.SimpleNamespace()
|
|
app.pipeline_mgr = types.SimpleNamespace(load_pipeline=_noop)
|
|
app.ver_mgr = types.SimpleNamespace(get_current_version=lambda: 'v4.11.1')
|
|
|
|
service = PipelineService.__new__(PipelineService)
|
|
service.ap = app
|
|
|
|
async def fake_get_default_config(context):
|
|
runner_id = 'plugin:langbot-team/LocalAgent/default'
|
|
return {
|
|
'ai': {
|
|
'runner': {'id': runner_id},
|
|
'runner_config': {runner_id: {'model': {'primary': '', 'fallbacks': []}}},
|
|
}
|
|
}
|
|
|
|
async def fake_get_pipelines(context, *args, **kwargs):
|
|
return []
|
|
|
|
async def fake_get_pipeline(context, uuid_value, include_secret=True):
|
|
return {'uuid': uuid_value}
|
|
|
|
async def fake_insert(statement):
|
|
captured['statement'] = statement
|
|
|
|
async def fake_limits(*args, **kwargs):
|
|
return {'max_pipelines': -1}
|
|
|
|
monkeypatch.setattr(service, 'get_default_pipeline_config', fake_get_default_config)
|
|
monkeypatch.setattr(service, 'get_pipelines', fake_get_pipelines)
|
|
monkeypatch.setattr(service, 'get_pipeline', fake_get_pipeline)
|
|
monkeypatch.setattr('langbot.pkg.api.http.service.workspace_limits.workspace_limits', fake_limits)
|
|
app.persistence_mgr.execute_async = fake_insert
|
|
|
|
await service.create_pipeline('workspace-a', {'name': 'de-agent-test'})
|
|
|
|
params = captured['statement'].compile().params
|
|
assert params.get('description') == ''
|
|
assert params.get('workspace_uuid') == 'workspace-a'
|