The GraphQL createProvider/updateProvider path applied no field validation, so
a direct API call (bypassing the browser's native HTML5 form validation) could
persist nonsensical values (temperature 99, negative price, an inverted
min/max length window, a reasoning budget over the 32000 engine cap).
Add ProviderConfig.Validate()/AgentConfig.Validate(), called after
patchProviderConfig in both CreateProvider and UpdateProvider. It is deliberately
permissive — 0 means "unset" and provider-specific tuning ranges remain the LLM
API's responsibility — so it only rejects universally-invalid values and never a
valid provider-specific config. Found during comprehensive provider QA.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The QA audit found minimax was wired into production everywhere but omitted
from provider-enumeration test data, so a future regression dropping it would
go uncaught. Add minimax to ProviderType.Valid()'s validTypes table, to the
GetSecretPatterns config (expected count 29→30, exercising the "MiniMax Key"
redaction pattern), and to clearConfigEnv's hermetic env list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks external PR #328 (octo-patch). The PR added only the provider core;
this brings MiniMax to full parity with the other providers (qwen) so it is
selectable and configurable in the UI and installer.
Applied from the PR (verified against MiniMax's official API docs — M3/M2.7/
M2.7-highspeed are real current models; corrected the M3 description from the
PR's "512K" to the documented ~1M context):
- minimax provider package (OpenAI-compatible https://api.minimax.io/v1),
config.yml, models.yml, tests; MINIMAX_API_KEY/SERVER_URL/PROVIDER env vars;
ProviderMiniMax type + DefaultProviderNameMiniMax; providers.go wiring;
Valid() whitelist.
Added for completeness:
- goose migration adding 'minimax' to the PROVIDER_TYPE enum + database
ProviderTypeMinimax const.
- GraphQL: minimax in ProviderType enum, ProvidersModelsList,
ProvidersReadinessStatus, DefaultProvidersConfig; resolvers wire default
config/models + enabled status; gqlgen regenerated.
- Frontend: MiniMax icon (lobehub), provider-icon + settings-providers
registration + provider type list; regenerated GraphQL types.
- Installer wizard: provider form, screen, list, registry, env-var mappings,
locale strings + help text.
- ctester/ftester: -type/-provider minimax support.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes audit-found coverage gaps:
- bedrock: TestBackstopForcesAdaptiveForAdaptiveOnlyModel (adaptive-only model
forces adaptive with no agent reasoning block) + a negative case for a
non-reasoning model. The Anthropic backstop already had an httptest test;
Bedrock had none.
- pconfig: ReasoningConfig.EffectiveMode (incl. max_tokens->budget inference)
and IsZero.
- converter: ConvertModels reasoning mapping (pconfig adaptive-only ->
GraphQL adaptive_only, efforts passthrough, nil for no descriptor).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extends adaptive-thinking support from Bedrock to the direct Anthropic provider.
langchaingo emits only budget thinking, so adaptive is applied by rewriting the
request body — for Anthropic via an http RoundTripper (the Messages API carries
thinking and sampling params at the top level), wired through the injectable
http.Client. prepareCallOptions forces adaptive for adaptive-only models (the
models.yml capability descriptor is the single source of truth) and stashes the
effort in context for the transport.
- adaptive_thinking.go: RoundTripper + rewrite (thinking->adaptive,
output_config.effort, display=summarized, strip temperature/top_p/top_k).
- models.yml: add claude-opus-4-7 / claude-opus-4-8 (adaptive-only) + reasoning
descriptors on the adaptive models (4.6/sonnet-4.6).
- Verified by a credit-free httptest integration test asserting the rewritten
body on the wire; the shape is also accepted by the real Anthropic API. Full
live e2e pending account credits/model access.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ModelConfig has custom UnmarshalYAML/UnmarshalJSON/MarshalYAML/MarshalJSON that
map fields by hand, so the reasoning capability descriptor added earlier was
silently dropped on load (Reasoning stayed nil). That made the Bedrock
adaptive-only backstop a no-op (modelReasoningMode never saw adaptive-only).
Handle `reasoning` in all four marshalers, mirroring `price`, plus a round-trip
regression test. Found via the anthropic adaptive integration test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds ModelReasoningInfo (mode + allowed efforts) to the GraphQL ModelConfig so
the frontend can gate the reasoning mode/effort UI by each model's declared
capability instead of a model-name regex. New ModelReasoningMode enum
(budget | adaptive | adaptive_only) mirrors the models.yml descriptor; the
converter maps pconfig adaptive-only -> GraphQL adaptive_only.
Backend groundwork for the Layer 2 frontend adaptive-thinking UI.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Makes adaptive-thinking models usable safely and adds Opus 4.7/4.8 to the
catalog so they are selectable and configurable.
- middleware: strip temperature/top_p/top_k and set thinking.display=summarized
when rewriting to adaptive. Opus 4.7+ reject sampling params (AWS: "no longer
supported", 400) and default display to "omitted" (empty reasoning text).
- models.yml: add us.anthropic.claude-opus-4-7 and us.anthropic.claude-opus-4-8,
plus a ModelReasoningInfo capability descriptor (mode + allowed efforts) on the
adaptive models (4.6/4.7/4.8/sonnet-4.6).
- provider backstop: force adaptive for adaptive-only models (Opus 4.7/4.8)
regardless of agent config, so selecting them cannot 400 on budget thinking.
The capability descriptor is the single source of truth (no model-name regex).
Verified: unit tests cover the body rewrite (sampling strip + display); a live
Bedrock run of the adaptive path on us.anthropic.claude-opus-4-6-v1 passed 21/23
(the 2 failures were 429 throttling, not the mechanism). Opus 4.7/4.8 could not
be exercised live -- this AWS account lacks model access (403), not a code
issue; their correctness rests on the AWS docs + the 4.6 live run + unit tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Integrates the backend half of PR #288 onto our branch (the frontend is
reworked separately in our codegen style), 3-way merged so the #233
config/models-path changes are preserved:
- adaptive_thinking.go: smithy Build middleware that rewrites the langchaingo
Converse body from thinking{type:enabled,budget_tokens} to
thinking{type:adaptive} + output_config.effort, wired via WithAPIOptions and
prepareCallOptions in Call/CallEx/CallWithTools.
- pconfig: ReasoningConfig.Mode (adaptive|budget) + EffectiveMode/IsZero.
- GraphQL: ReasoningMode enum, reasoning.mode field, xhigh/max effort levels.
Drops the dead llms.WithMetadata adaptive branch from AgentConfig.BuildOptions
(nothing reads opts.Metadata on the Bedrock path; adaptive is applied per-call
by the provider) and updates the unit test accordingly.
Hardening still pending (next commit): strip temperature/top_p/top_k and set
display:summarized for adaptive requests, add Opus 4.7/4.8 catalog entries with
a model reasoning-capability descriptor + force-adaptive backstop, and a live
Bedrock repro. Until then Opus 4.7 should not be selected for an agent.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks PR #233 to follow the existing config-path pattern and make an
externally-added Bedrock model fully usable from the web UI.
- BEDROCK_CONFIG_PATH: replace the embedded per-agent config (model
assignments + prices), mirroring OLLAMA_SERVER_CONFIG_PATH /
LLM_SERVER_CONFIG_PATH. DefaultProviderConfig now takes *config.Config
and reads the external file when set, else the embedded config.yml.
- BEDROCK_MODELS_PATH: merge an external model catalog onto the embedded
models.yml so new ids appear and are selectable under Settings ->
Providers. DefaultModels now takes *config.Config and the resolver +
provider construction pass it through; new ids are added, a matching
name overrides the embedded entry.
Wires both through docker-compose, .env.example, config.md and the README,
and ships examples/configs/bedrock-glm-flash.{provider,models}.yml using the
real AWS Bedrock id zai.glm-4.7-flash (In-Region, no inference-profile
prefix, 4K max output).
Dropped from #233: the ProviderConfig.Name field and the SeedDefaultProviders
mechanism (a per-user DB write fired on startup and inside the read-only
SettingsProviders resolver) -- the config already reaches the UI through
DefaultProvidersConfig without any DB rows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Disabled-by-default audit feature (EVIDENCE_RECEIPTS_ENABLED): appends a
hash-chained JSONL receipt per finished/failed toolcall under
<DATA_DIR>/flow-<id>/evidence/receipts.jsonl, recording toolcall
provenance plus SHA-256 hashes of args/result (no raw content).
Integration adapted to current main: the original PR built the receipt
from a database.Toolcall returned by ce.db.UpdateToolcall*Result, which
the executor no longer uses after the ToolCallLogProvider (tclp) refactor.
Receipts are now built from the in-scope toolcall data at the tclp log
sites and recorded non-fatally, so a receipt failure is logged and never
fails an otherwise-successful toolcall.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Commit the ZIP response status and headers lazily, on the first byte written, via a small zipStreamWriter. A build failure before any output now returns the normal structured error response instead of a committed 200 with a truncated body; mid-stream failures still abort. Also check the reader Close error in the helper test and cover the pre-stream failure path.
DownloadResource and DownloadFlowFile built the entire ZIP archive in a bytes.Buffer before sending it, so heap usage scaled with archive size and a few concurrent large-directory downloads could exhaust process memory.
Stream the archive straight to the response writer via a shared streamZipArchive helper; the existing ZipResources/ZipDirectory/ZipRelativePaths helpers already accept an io.Writer. Responses are now chunked (no Content-Length) and memory stays proportional to one file's copy buffer.
Rename a knowledge document via a dedicated mutation that rewrites only the
question in cmetadata — no re-embedding, no embedder required — mirroring the
flows renameFlow pattern instead of round-tripping the full document through
updateKnowledgeDocument.
Backend:
- renameKnowledgeDocument(id, question) mutation + resolver (admin/user split;
ownership enforced at GetUserDocument, like the update pair)
- metadata-only query UpdateKnowledgeDocumentMetadata (no migration)
- unit + edge tests: metadata-only, missing-doc error, non-owner rejection
Frontend:
- renameKnowledge provider method; wire list and detail inline-rename to it
- drop the content "Preview" column and request the list with withContent:false
so it no longer pulls full document bodies
Verified end to end against a local Docker backend (rename works; content and
embedding preserved) and against the remote backend (graceful failure where the
mutation is not yet deployed).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ChangeNameCurrentUser issued a bare UPDATE and ignored RowsAffected, so a stale
session for a deleted user got 200 — inconsistent with the email/password handlers
(which 404) and leaving the frontend's Users.NotFound mapping unreachable.
- check RowsAffected and return ErrUsersNotFound (404) when no row matched
- document the 404 in the swagger annotation
- add TestChangeNameCurrentUser (success, missing user, invalid name)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The vmail validator rejected addresses the frontend's z.string().email() accepts
(uppercase, TLDs longer than 4 chars like .cloud), so users saw a confusing 400.
- relax the vmail regex to allow uppercase and TLDs of 2+ chars
- lowercase + trim the new address in ChangeEmailCurrentUser and in the form schema
so storage, the duplicate check, and login lookups stay case-stable
- validator + change-email tests for mixed case and long TLDs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- authLoginCallback matches users by email alone so an OAuth login links into an
existing (incl. local) account instead of 500-ing on users_mail_unique
- relink on a create-branch unique-violation race instead of returning 500
- issue the session with the linked account's actual role privileges
- clear the stale OAuth provider link when a user changes their email
- map the email-change unique-violation race to 409 instead of 500
- isUniqueViolation matches Postgres and SQLite case-insensitively
- tests for link/create/blocked/role-inheritance/race, email 409, provider reset
- update auth form test selectors after the form refactor
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- OAuth login callback now stores the provider (google/github) on the
user record and backfills it for pre-existing OAuth users on login,
so the UI can show which provider an account is linked to.
- Add PUT /user/name for any authenticated user (including OAuth): a
NameChange model + ChangeNameCurrentUser handler that lets users edit
their display name. Placed in a /user group without localUserRequired.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two crashes seen in production, both reproduced on the live app:
- "Failed to fetch dynamically imported module": after a redeploy rotates the
hashed chunk filenames, an open tab imports a deleted one. The server answered a
missing /assets/* with 301 -> index.html (HTML for a JS module -> a MIME
failure); it now returns 404 + no-store. The client listens for Vite's
vite:preloadError and reloads once (debounced) to pull the current build. Hashed
assets are served immutable; index.html and SPA routes no-cache.
- "Failed to execute 'removeChild' ... not a child of this node": an external
agent (a browser extension or auto-translation) mutates the DOM React owns,
desyncing reconciliation. A root react-router errorElement catches this
commit-phase crash and self-heals with a debounced reload, instead of React
Router's dead default error screen. translate="no" opts the English-only UI out
of the one trigger it can prevent (browser translation); the errorElement covers
the rest regardless of source.
Verified by reproducing both on the live old build (missing-chunk 301->HTML;
extension/translation DOM mutation -> the exact removeChild crash) and confirming
the fixed build recovers from each. Adds chunk-reload + RouteErrorBoundary unit
tests and a static-serving integration test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes#312
Root cause:
During flow creation the first LLM call selects the primary Docker
image. When the configured LLM backend is unsupported or returns 404,
prv.Call fails, but the wrapped error read "failed to get primary
docker image". Users repeatedly interpreted this as a Docker problem
(see #312, #309, #203) and debugged Docker instead of their LLM
provider configuration.
Solution:
Reword the wrapped error to "failed to select primary docker image
via llm call" so the LLM provider is identified as the failing
component while still mentioning the image selection step.
Testing:
go build ./pkg/providers/ -> OK
Added new test cases to validate containment barriers in the `ResolvePulledStagedTarget` and `ZipRelativePaths` functions, ensuring that paths escaping the designated directories are properly rejected. Updated the `knowledge_test.go` to include scenarios for handling nil embedder and error propagation during document creation, improving overall test coverage and robustness.
Enhanced the flowWorker's task processing by introducing a cancellable context for task execution. This change ensures that tasks can be properly cancelled without reporting false success states. The `runTask` method has been refactored to utilize a new `execTask` method, which centralizes task execution logic and maintains context integrity. This update improves flow control and error handling during task creation and execution.
Updated the Qwen agent configuration to include `extra_body` parameters for thinking control across various models. Added `enable_thinking` and `preserve_thinking` options for reasoning agents, while utility agents have `enable_thinking` set to false. Adjusted the Qwen client initialization to support these new configurations. Updated test report to reflect changes in success rates and latencies.
DeepSeek V4 thinking mode defaults to enabled on both deepseek-v4-flash
and deepseek-v4-pro; non-thinking behavior requires an explicit toggle.
Per official docs, in thinking mode temperature/top_p/presence_penalty/
frequency_penalty are ignored, so the existing Flash role sampling knobs
would have been silently no-ops without the toggle.
Add extra_body.thinking.type=disabled to the five non-thinking Flash
roles so deepseek-v4-flash actually runs in non-thinking mode and
honors the role's temperature/top_p settings:
- simple, simple_json, adviser, searcher, enricher
Pro roles (primary_agent, assistant, generator, refiner, reflector,
coder, installer, pentester) intentionally keep thinking enabled (the
V4 default) for reasoning, tool-use, and security analysis.
PentAGI provider config already supports extra_body as a first-class
yaml field on AgentConfig and forwards it through openai.WithExtraBody,
which the vxcontrol langchaingo fork serializes at the top level of the
Chat Completions request - the same pattern Kimi uses for tool_choice.
No code, schema, or LiteLLM prefix changes required.
Touches:
- backend/pkg/providers/deepseek/config.yml (embedded production config)
- examples/configs/deepseek.provider.yml (user-facing example)
No change to role-to-model mapping, model metadata, pricing, README
wording, LiteLLM prefix, unrelated providers, lifecycle, queues, or
installer flow.
- Update model descriptions to reflect V4 1M context window (up to 384K output)
instead of legacy 128K wording in models.yml and README.
- Split Flash and Pro pricing per official DeepSeek API docs:
- deepseek-v4-flash: input 0.14 / output 0.28 / cache_hit 0.0028 per 1M tokens
- deepseek-v4-pro: input 0.435 / output 0.87 / cache_hit 0.003625 per 1M tokens
- Apply per-role price split across all 13 role configs in both the embedded
config.yml and the user-facing examples/configs/deepseek.provider.yml.
- Replace stale "cache pricing is 10% of input cost" claim in the README,
which no longer holds for either V4 model.
- No change to LiteLLM prefix behavior, role-to-model mapping, lifecycle,
queues, GraphQL schema, migrations, frontend, or installer flow.
The DeepSeek provider config still defaulted to the legacy
`deepseek-chat` and `deepseek-reasoner` model names, which the
upstream DeepSeek API has announced for deprecation on 2026-07-24.
A first-run install therefore breaks once the legacy names are
removed.
Swap the defaults to the current DeepSeek V4 family:
- non-thinking roles use `deepseek-v4-flash`
- reasoning-heavy roles use `deepseek-v4-pro`
The change is limited to the embedded `config.yml` / `models.yml`
inside `backend/pkg/providers/deepseek`, the matching example at
`examples/configs/deepseek.provider.yml`, the `DeepSeekAgentModel`
fallback constant in `deepseek.go`, and three doc references
(README.md, backend/docs/config.md, backend/docs/llms_how_to.md)
plus one installer help string in
`backend/cmd/installer/wizard/locale/locale.go`. LiteLLM prefix
behavior is untouched.
- Introduced `EMBEDDING_MAX_TEXT_BYTES` to limit the maximum byte size of text sent to the embedding model.
- Renamed database connection pool settings: `DATABASE_MAX_OPEN_CONNS`, `DATABASE_MAX_IDLE_CONNS`, and `DATABASE_VECTOR_MAX_CONNS` for improved PostgreSQL connection management.
- Updated relevant documentation to reflect these new configuration options and their usage.
- Adjusted various components to utilize the new settings for enhanced performance and resource management.
- Added ToolCallLogProvider interface with methods for logging tool calls, updating success and failure statuses.
- Introduced proxyToolCallLogProvider to handle ToolCall logging operations.
- Updated flow execution components to integrate ToolCall logging, including flow workers and controllers.
- Enhanced GraphQL schema to support ToolCall logs, including queries and subscriptions for real-time updates.
- Updated documentation to reflect the new ToolCall logging features and their usage.
- Introduced shared connection pooling for PostgreSQL using `*sql.DB` for sqlc and GORM, optimizing resource usage.
- Added new environment variables: `DB_MAX_OPEN_CONNS`, `DB_MAX_IDLE_CONNS`, and `DB_VECTOR_MAX_CONNS` for configurable connection limits.
- Updated documentation to reflect new connection pooling strategy and provide operational commands for monitoring.
- Implemented shared `pgxpool` for pgvector stores to reduce connection overhead and improve performance.
- Adjusted various components to utilize the new connection pooling setup, ensuring efficient database interactions.
- Introduced WaitTaskCompletion method in FlowWorker interface to block until the current task completes or the context expires.
- Implemented signalTaskComplete to manage task completion signaling across goroutines.
- Added waitFlowCompletion tool to handle waiting for task completion with configurable timeout.
- Updated assistant provider to include wait functionality for flow completion.
- Enhanced templates and tool registry to support new wait functionality.
When an LLM emits a truncated or malformed arguments field (e.g. "{") instead of valid JSON, downstream consumers such as LiteLLM reject the entire request with a 400 Bad Request, causing the chain to degrade into an infinite retry loop.
- SanitizeToolCallArguments now falls back to "{}" after control-char escaping if the result is still not valid JSON, fixing already-stored chains on restore
- callWithRetries logs a warning and substitutes "{}" at the moment the bad arguments arrive from the LLM, preventing them from ever reaching the database
- Added test cases for truncated JSON, partial objects, and empty strings
- Added a new SQL migration to insert toolcall privileges into the privileges table.
- Introduced the `ToolcallService` for managing toolcall data, including retrieval of toolcalls and flow-specific toolcalls.
- Implemented API endpoints for fetching toolcalls and toolcall details, with appropriate permission checks.
- Enhanced Swagger documentation to include new toolcall endpoints and their specifications.
- Created a new model for toolcalls, defining their structure and validation rules.
- Added error handling for invalid toolcall requests and not found scenarios.
- Added a new SQL migration to insert the 'anonymize.call' privilege into the privileges table.
- Introduced the `anonymizeText` mutation in the GraphQL schema, allowing users to anonymize sensitive text.
- Implemented the `AnonymizerService` to handle text anonymization requests via a REST API endpoint.
- Updated the GraphQL resolver to integrate the new mutation and ensure proper permission checks.
- Enhanced documentation with Swagger and OpenAPI specifications for the new endpoint.
- Added error handling for invalid requests and unavailable anonymizer configurations.
Eliminate the message length truncation from both `putMsg` methods in `aslog.go` and `msglog.go`. This change simplifies the message handling process by allowing messages to be processed without arbitrary length restrictions.
- Fix empty ID bug: langchaingo SimilaritySearch discarded document UUIDs; new SearchKnowledgeDocuments/SearchUserKnowledgeDocuments return them directly
- Remove unsafe fmt.Sprintf SQL filter interpolation, use parameterised queries
- Exclude memory documents from search results at SQL level
- Add FlowID support to passesSearchFilter
- Convert all $N positional params to sqlc.arg(name) across knowledge queries
- Update tests: replace TestBuildSearchFilters with TestPassesSearchFilter, add TestSearchDocuments and TestSearchUserDocuments
- Introduced a new `docType` field in the `UpdateKnowledgeDocumentInput` to manage document type changes.
- Updated the `doUpdate` method to clear subtype fields (GuideType, AnswerType, CodeLang) when the document type changes.
- Added comprehensive tests for various document type transitions to ensure correct behavior and state preservation.
- Updated GraphQL schema and generated models to accommodate the new `docType` field.
- Introduced "/resources" and "/knowledges" routes to the frontendRoutes array in the router configuration, expanding the application's routing capabilities.
- Removed the requirement for the "destination" field in MoveResourceRequest, allowing it to be an empty string, which signifies moving to the root directory.
- Updated related documentation in swagger.json, swagger.yaml, and docs.go to reflect the new behavior.
- Adjusted the MoveResource function to handle cases where the destination is empty, ensuring proper path sanitization and resource movement semantics.
- Enhanced test cases to cover scenarios involving moving resources to the root directory and handling conflicts appropriately.
- Allow POST /flows/0/assistants/ to create a new flow together with the assistant, mirroring the existing GraphQL createAssistant(flowID: 0) behavior
- Require both assistants.create and flows.create permissions when flowID=0
- Add explicit flow ownership check for non-zero flowID using flows.admin scope
- Load flow data in the response by fetching it via assistant.FlowID after creation, ensuring AssistantFlow is fully populated in all cases
- Introduced new fields `version` and `isDevelopMode` in the Settings model to provide application versioning and development mode status.
- Updated GraphQL schema and resolvers to support the new fields, ensuring they are accessible via the Settings query.
- Enhanced Swagger documentation to reflect the changes in the Settings API endpoint.
- Added necessary validation and response handling for the new fields in the Settings service.