mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-11 16:26:02 +00:00
Compare commits
4 Commits
v4.10.0-be
...
v4.10.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fee7d48dc3 | ||
|
|
8811fb647f | ||
|
|
37b017459d | ||
|
|
4889a3881b |
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "langbot"
|
name = "langbot"
|
||||||
version = "4.10.0-beta.3"
|
version = "4.10.0"
|
||||||
description = "Production-grade platform for building agentic IM bots"
|
description = "Production-grade platform for building agentic IM bots"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""LangBot - Production-grade platform for building agentic IM bots"""
|
"""LangBot - Production-grade platform for building agentic IM bots"""
|
||||||
|
|
||||||
__version__ = '4.10.0-beta.3'
|
__version__ = '4.10.0'
|
||||||
|
|||||||
@@ -459,7 +459,7 @@ class PluginRuntimeConnector(ManagedRuntimeConnector):
|
|||||||
)
|
)
|
||||||
|
|
||||||
file_bytes = download_resp.content
|
file_bytes = download_resp.content
|
||||||
self._extract_deps_metadata(file_bytes, task_context)
|
self._inspect_plugin_package(file_bytes, task_context)
|
||||||
file_key = await self.handler.send_file(file_bytes, 'lbpkg')
|
file_key = await self.handler.send_file(file_bytes, 'lbpkg')
|
||||||
install_info['plugin_file_key'] = file_key
|
install_info['plugin_file_key'] = file_key
|
||||||
self.ap.logger.info(f'Transfered file {file_key} to plugin runtime')
|
self.ap.logger.info(f'Transfered file {file_key} to plugin runtime')
|
||||||
|
|||||||
@@ -143,49 +143,83 @@ class ModelManager:
|
|||||||
# get the latest models from space
|
# get the latest models from space
|
||||||
space_models = await self.ap.space_service.get_models()
|
space_models = await self.ap.space_service.get_models()
|
||||||
|
|
||||||
exists_llm_models_uuids = [m['uuid'] for m in await self.ap.llm_model_service.get_llm_models()]
|
# Index existing models by uuid. Space reuses a model's uuid across
|
||||||
exists_embedding_models_uuids = [
|
# renames / re-specs (e.g. the uuid that used to be ``claude-opus-4-6``
|
||||||
m['uuid'] for m in await self.ap.embedding_models_service.get_embedding_models()
|
# may later become ``claude-opus-4-7``). So for Space-managed models we
|
||||||
]
|
# upsert: create when the uuid is new, otherwise update name/abilities/
|
||||||
|
# ranking to track Space. Models owned by other providers are never
|
||||||
|
# touched, even on an (unexpected) uuid collision.
|
||||||
|
existing_llm_models = {m['uuid']: m for m in await self.ap.llm_model_service.get_llm_models()}
|
||||||
|
existing_embedding_models = {
|
||||||
|
m['uuid']: m for m in await self.ap.embedding_models_service.get_embedding_models()
|
||||||
|
}
|
||||||
|
|
||||||
|
created = 0
|
||||||
|
updated = 0
|
||||||
|
|
||||||
for space_model in space_models:
|
for space_model in space_models:
|
||||||
if space_model.category == 'chat':
|
if space_model.category == 'chat':
|
||||||
uuid = space_model.uuid
|
existing = existing_llm_models.get(space_model.uuid)
|
||||||
|
if existing is None:
|
||||||
if uuid in exists_llm_models_uuids:
|
# model will be automatically loaded
|
||||||
continue
|
await self.ap.llm_model_service.create_llm_model(
|
||||||
|
{
|
||||||
# model will be automatically loaded
|
'uuid': space_model.uuid,
|
||||||
await self.ap.llm_model_service.create_llm_model(
|
'name': space_model.model_id,
|
||||||
{
|
'provider_uuid': space_model_provider.uuid,
|
||||||
'uuid': space_model.uuid,
|
'abilities': space_model.llm_abilities or [],
|
||||||
|
'extra_args': {},
|
||||||
|
'prefered_ranking': space_model.featured_order,
|
||||||
|
},
|
||||||
|
preserve_uuid=True,
|
||||||
|
auto_set_to_default_pipeline=False,
|
||||||
|
)
|
||||||
|
created += 1
|
||||||
|
elif existing.get('provider_uuid') == space_model_provider.uuid:
|
||||||
|
desired = {
|
||||||
'name': space_model.model_id,
|
'name': space_model.model_id,
|
||||||
'provider_uuid': space_model_provider.uuid,
|
'provider_uuid': space_model_provider.uuid,
|
||||||
'abilities': space_model.llm_abilities or [],
|
'abilities': space_model.llm_abilities or [],
|
||||||
'extra_args': {},
|
|
||||||
'prefered_ranking': space_model.featured_order,
|
'prefered_ranking': space_model.featured_order,
|
||||||
},
|
}
|
||||||
preserve_uuid=True,
|
if (
|
||||||
auto_set_to_default_pipeline=False,
|
existing.get('name') != desired['name']
|
||||||
)
|
or list(existing.get('abilities') or []) != list(desired['abilities'])
|
||||||
|
or existing.get('prefered_ranking') != desired['prefered_ranking']
|
||||||
|
):
|
||||||
|
await self.ap.llm_model_service.update_llm_model(space_model.uuid, dict(desired))
|
||||||
|
updated += 1
|
||||||
|
|
||||||
elif space_model.category == 'embedding':
|
elif space_model.category == 'embedding':
|
||||||
uuid = space_model.uuid
|
existing = existing_embedding_models.get(space_model.uuid)
|
||||||
|
if existing is None:
|
||||||
if uuid in exists_embedding_models_uuids:
|
# model will be automatically loaded
|
||||||
continue
|
await self.ap.embedding_models_service.create_embedding_model(
|
||||||
|
{
|
||||||
# model will be automatically loaded
|
'uuid': space_model.uuid,
|
||||||
await self.ap.embedding_models_service.create_embedding_model(
|
'name': space_model.model_id,
|
||||||
{
|
'provider_uuid': space_model_provider.uuid,
|
||||||
'uuid': space_model.uuid,
|
'extra_args': {},
|
||||||
|
'prefered_ranking': space_model.featured_order,
|
||||||
|
},
|
||||||
|
preserve_uuid=True,
|
||||||
|
)
|
||||||
|
created += 1
|
||||||
|
elif existing.get('provider_uuid') == space_model_provider.uuid:
|
||||||
|
desired = {
|
||||||
'name': space_model.model_id,
|
'name': space_model.model_id,
|
||||||
'provider_uuid': space_model_provider.uuid,
|
'provider_uuid': space_model_provider.uuid,
|
||||||
'extra_args': {},
|
|
||||||
'prefered_ranking': space_model.featured_order,
|
'prefered_ranking': space_model.featured_order,
|
||||||
},
|
}
|
||||||
preserve_uuid=True,
|
if (
|
||||||
)
|
existing.get('name') != desired['name']
|
||||||
|
or existing.get('prefered_ranking') != desired['prefered_ranking']
|
||||||
|
):
|
||||||
|
await self.ap.embedding_models_service.update_embedding_model(space_model.uuid, dict(desired))
|
||||||
|
updated += 1
|
||||||
|
|
||||||
|
if created or updated:
|
||||||
|
self.ap.logger.info(f'Synced models from LangBot Space: {created} added, {updated} updated.')
|
||||||
|
|
||||||
async def init_temporary_runtime_llm_model(
|
async def init_temporary_runtime_llm_model(
|
||||||
self,
|
self,
|
||||||
|
|||||||
2
uv.lock
generated
2
uv.lock
generated
@@ -1899,7 +1899,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langbot"
|
name = "langbot"
|
||||||
version = "4.10.0b3"
|
version = "4.10.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiocqhttp" },
|
{ name = "aiocqhttp" },
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from '@/components/ui/popover';
|
} from '@/components/ui/popover';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ScannedProviderModel } from '@/app/infra/entities/api';
|
import { ScannedProviderModel } from '@/app/infra/entities/api';
|
||||||
import {
|
import {
|
||||||
@@ -298,20 +298,8 @@ export default function AddModelPopover({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="overflow-y-auto flex-1 min-h-0">
|
<div className="overflow-y-auto flex-1 min-h-0">
|
||||||
<Tabs
|
{mode === 'manual' ? (
|
||||||
value={mode}
|
<div className="mt-3">
|
||||||
onValueChange={(v) => setMode(v as 'manual' | 'scan')}
|
|
||||||
>
|
|
||||||
{!trigger && (
|
|
||||||
<TabsList className="grid w-full grid-cols-2 mt-3">
|
|
||||||
<TabsTrigger value="manual">
|
|
||||||
{t('models.manualAdd')}
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="scan">{t('models.scanAdd')}</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<TabsContent value="manual" className="mt-3">
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>{t('models.modelName')}</Label>
|
<Label>{t('models.modelName')}</Label>
|
||||||
@@ -390,9 +378,9 @@ export default function AddModelPopover({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</div>
|
||||||
|
) : (
|
||||||
<TabsContent value="scan" className="space-y-2 mt-0 pt-0">
|
<div className="space-y-2 mt-3">
|
||||||
{scanLoading ? (
|
{scanLoading ? (
|
||||||
<div className="flex items-center justify-center py-4">
|
<div className="flex items-center justify-center py-4">
|
||||||
<RefreshCw className="h-4 w-4 mr-2 animate-spin text-muted-foreground" />
|
<RefreshCw className="h-4 w-4 mr-2 animate-spin text-muted-foreground" />
|
||||||
@@ -565,8 +553,8 @@ export default function AddModelPopover({
|
|||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</div>
|
||||||
</Tabs>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user