mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-22 16:35:20 +08:00
feat(operation-trace): record which resource was touched and what changed
Granularity follow-up: a record used to say only "installed an extension". - Add resolve_resource_identity(): derive the acted-on resource from trusted route params or the install-style payload (plugin_author/plugin_name), so every resource family names its target. Unknown keys are ignored and sensitive keys are skipped, keeping the audit trail bounded and secret-free. - The route wrapper applies it to every traced request; the identity only fills in when a handler did not publish a more precise one. - Publish field-level before/after diffs for plugin config, skill, knowledge base, MCP server, pipeline, provider and model updates, reusing changed_fields()/build_summary() so secret-looking keys stay redacted and a masked round-trip never shows up as a phantom change.
This commit is contained in:
@@ -3,6 +3,7 @@ import quart
|
||||
from langbot.pkg.provider.modelmgr import errors as provider_errors
|
||||
from ....authz import Permission, has_permission
|
||||
from ....context import RequestContext
|
||||
from ....service import settings as settings_service
|
||||
from ... import group
|
||||
from .query import resolve_include_secret
|
||||
|
||||
@@ -85,14 +86,28 @@ class LLMModelsRouterGroup(group.RouterGroup):
|
||||
permission=Permission.PROVIDER_SECRET_MANAGE,
|
||||
)
|
||||
async def _(model_uuid: str, request_context: RequestContext) -> str:
|
||||
json_data = await quart.request.json
|
||||
try:
|
||||
previous = await self.ap.llm_model_service.get_llm_model(request_context, model_uuid)
|
||||
except Exception:
|
||||
previous = None
|
||||
try:
|
||||
await self.ap.llm_model_service.update_llm_model(
|
||||
request_context,
|
||||
model_uuid,
|
||||
await quart.request.json,
|
||||
json_data,
|
||||
)
|
||||
except ValueError as exc:
|
||||
return self.http_status(400, -1, str(exc))
|
||||
changes = settings_service.changed_fields(
|
||||
previous if isinstance(previous, dict) else {},
|
||||
json_data if isinstance(json_data, dict) else {},
|
||||
ignore=('uuid', 'created_at', 'updated_at'),
|
||||
)
|
||||
rule = settings_service.ACTION_RULES_BY_ACTION.get('update')
|
||||
quart.g.operation_log_changes = changes
|
||||
if rule is not None and changes:
|
||||
quart.g.operation_log_summary = settings_service.build_summary(rule, changes)
|
||||
return self.success()
|
||||
|
||||
@self.route(
|
||||
|
||||
@@ -2,6 +2,7 @@ import quart
|
||||
|
||||
from ....authz import Permission, has_permission
|
||||
from ....context import RequestContext
|
||||
from ....service import settings as settings_service
|
||||
from ... import group
|
||||
from .query import resolve_include_secret
|
||||
|
||||
@@ -155,10 +156,29 @@ class ModelProvidersRouterGroup(group.RouterGroup):
|
||||
)
|
||||
async def _(provider_uuid: str, request_context: RequestContext) -> str:
|
||||
json_data = await quart.request.json
|
||||
try:
|
||||
previous = await self.ap.provider_service.get_provider(
|
||||
request_context,
|
||||
provider_uuid,
|
||||
include_secret=True,
|
||||
)
|
||||
except Exception:
|
||||
previous = None
|
||||
try:
|
||||
await self.ap.provider_service.update_provider(request_context, provider_uuid, json_data)
|
||||
except ValueError as exc:
|
||||
return self.http_status(400, -1, str(exc))
|
||||
# Record which provider was reconfigured and which fields moved;
|
||||
# credential-looking keys are redacted by ``changed_fields``.
|
||||
changes = settings_service.changed_fields(
|
||||
previous if isinstance(previous, dict) else {},
|
||||
json_data if isinstance(json_data, dict) else {},
|
||||
ignore=('uuid', 'created_at', 'updated_at', 'llm_count', 'embedding_count', 'rerank_count'),
|
||||
)
|
||||
rule = settings_service.ACTION_RULES_BY_ACTION.get('update')
|
||||
quart.g.operation_log_changes = changes
|
||||
if rule is not None and changes:
|
||||
quart.g.operation_log_summary = settings_service.build_summary(rule, changes)
|
||||
return self.success()
|
||||
|
||||
@self.route(
|
||||
|
||||
Reference in New Issue
Block a user