Skip to content

Agent v3 chat - #832

Open
charles-ramos wants to merge 68 commits into
production2from
agent-v3-chat
Open

Agent v3 chat#832
charles-ramos wants to merge 68 commits into
production2from
agent-v3-chat

Conversation

@charles-ramos

Copy link
Copy Markdown
Member

New Pull Request Checklist

Issue Description

Closes: FILL_THIS_OUT

Approach

TODOs before merging

  • Add tests
  • Add changes to documentation (guides, repository pages, in-code descriptions)

charles-ramos and others added 30 commits August 21, 2026 22:42
Fase A do porte production1 -> production2:
- src/dashboard/Data/Agent/ (Agent.react.js, Agent.scss, AgentConfigDialog.react.js)
  e src/lib/AgentService.js
- Empty state com B4aEmptyState + botao Configure; dialog com B4aFormModal (padrao
  visual do production2)
- Form "Configure" (localStorage, provider OpenAI) para o usuario informar a apiKey
  pela UI, sem editar o config.json
- Rota /agent no Dashboard.js + secao Agent na sidebar (DashboardView)
- Parse-Dashboard/app.js: porta a rota POST /apps/:appId/agent + makeOpenAIRequest +
  database tools + conversas; adiciona require('parse/node'); usa fetch global (Node 18,
  sem node-fetch); express.json() escopado so na rota (production2 nao tem body-parser global)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O package.json declarava core-js em 3.28.0 (dependencies) e 3.6.5 (devDependencies).
Sem lockfile, o npm install deixava o 3.6.5 no topo, que nao tem modulos como
es.error.cause.js/es.array.at.js/etc. O babel usa corejs '3.28' (useBuiltIns 'entry'),
entao o `npm run dashboard` (webpack build.config.js) quebrava com ~40 erros
"Can't resolve 'core-js/modules/...'". Alinhado ambos para 3.28.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sem lockfile, o npm resolvia um tslib antigo (sem __spreadArray) no topo. O
@amplitude/analytics-core chama tslib.__spreadArray em runtime -> TypeError ->
tela branca no dashboard. tslib e transitivo (nao esta no package.json), entao
forcei via "overrides" para 2.6.2 (tem __spreadArray, retrocompativel).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uction2

- Agent.scss convertido do tema claro (production1) para o dark do production2:
  fundo #0f1c32, superficies/bolhas/input escuros, texto claro, acento azul.
  Layout/estrutura mantidos.
- Toolbar: section "Core" -> "Agent" (breadcrumb correto).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Porta da production1 os constraints que faltavam no production2:
- matches (regex, String) -> query.matches(field, str, modifiers)
- onOrBefore (Date) -> query.lessThanOrEqualTo
- onOrAfter (Date) -> query.greaterThanOrEqualTo
Definicoes em Constraints + FieldConstraints (String/Date) em src/lib/Filters.js,
e os cases correspondentes em src/lib/queryFromFilters.js. O production2 ja tinha
neq/keyNeq/stringContainsString.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…que)

O BrowserCell do production2 importa B4aBrowserCell.scss, que NAO tinha as classes
.selected/.leftBorder/.rightBorder/.topBorder/.bottomBorder. A logica de selecao
(handleCellClick + selectedCells) ja funcionava, mas classes.push(styles.selected)
empurrava undefined -> celula selecionava internamente mas nao pintava (nenhum erro
no console). Copiadas as 5 regras do BrowserCell.scss normal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…curo

- Cmd/Ctrl+C agora copia o INTERVALO de celulas selecionadas (tab/newline), nao so a
  celula focada. No production2 o range faz setCurrent(null) -> copyableValue undefined
  -> o case 67 existente nao copiava nada. Adicionado o copy multi-celula no topo do
  handleKey (guard >= 0 pra nao quebrar no estado inicial).
- .selected: de #e3effd (claro) para rgba(22,105,252,.3) e bordas #1669fc — legivel no
  Data Browser escuro do production2 (antes o texto claro sumia no fundo azul-claro).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Portado da production1: no handleKey, case 32 (Space) faz toggle do selectRow da
linha "current" (quando nao esta editando). production2 nao tinha esse case.
Guards para this.props.selectRow/selection/data existirem.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lique pegar

O checkbox usava checked={selection['*'] || selection[obj.id]} sem coercao — quando
selection[id] era undefined, o input virava NAO-controlado, e a transicao
nao-controlado->controlado no clique fazia o React nao registrar a marcacao. Coercao
com !! (igual production1) mantem o input sempre controlado. O espaco ja funcionava
porque ia direto no selectRow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(upstream)

Porta a feature drag-to-select da production1: mousedown num checkbox inicia o
arrasto, cada checkbox que o mouse passa por cima marca/desmarca, mouseup encerra.
- Browser.react: estado rowCheckboxDragging/draggedRowSelection, metodos
  onMouseDownRowCheckBox/onMouseUpRowCheckBox/onMouseOverRowCheckBox, listener global
  de mouseup, e passa os handlers pro DataBrowser (fluem via ...other ao BrowserTable).
- BrowserTable: repassa onMouseDown/OverRowCheckBox aos 3 <BrowserRow>.
- BrowserRow: checkbox com onMouseDown, checkCell com onMouseOver.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orage

Agora que o pre-production2 tem getEnvVars/updateEnvVars (feature do production2):
- Configure -> Save: grava a apiKey na env var OPENAI_API_KEY do app (merge com as
  existentes via getEnvVars); dispara rebuild do app (comportamento da feature).
- Agent carrega: le a apiKey via getEnvVars; partes nao-secretas (name/provider/model)
  ficam em localStorage. A chave nunca persiste no disco do browser.
- Dialog: onSubmit retorna a promise -> modal mostra "Saving..." durante o rebuild e
  surface erros. Descricao do campo API Key atualizada.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- icon 'collaborate-solid' (nao existia no sprite -> item sem icone) trocado por
  'b4a-agent' (icone dedicado que ja existe em src/icons).
- Remove subsections: [] -> o Sidebar renderizava um submenu VAZIO (bloco grande em
  branco abaixo de "Agent"). Sem a chave subsections, o item fica compacto como o
  "Overview".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rtilhada

- AgentConfigDialog vira gerenciador de lista: 1 API Key compartilhada + N modelos
  (Display name + model), com "+ Add model" e "Remove" por modelo.
- saveAgentConfig({apiKey, models}): grava a chave no env var OPENAI_API_KEY (uma so)
  e a lista de modelos (nao-secreta) no localStorage; monta em memoria cada modelo
  com a chave compartilhada.
- loadAgentConfig: le a lista do localStorage + a chave do env var.
- O seletor "Model" no toolbar do Agent ja itera models -> troca entre eles.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Troca os icones dos menus do toolbar do Agent (que vieram do upstream) pelos B4a:
- Model: gear-solid -> b4a-app-settings-icon
- Permissions: locked-solid -> b4a-lock-icon
- Chat: collaborate-solid -> b4a-agent

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- B4aSidebarSection.getIconContent nao tinha case pro 'b4a-agent' -> no estado ATIVO
  caia no default (null) e o icone sumia. Add case que renderiza o sprite b4a-agent.
- AgentConfigDialog: "+ Add model" (link no rodape) vira um botao "+"
  (b4a-add-outline-circle) no topo da secao Models, seguindo o padrao de "adicionar row".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Layout (offsets eram da production1):
- left 300px -> 280px ($b4aSidebarWidth) no emptyStateOverlay e chatForm
- top/padding-top 116px -> 127px (header 63 + toolbar 64 do production2)
- sidebar colapsada: $sidebarCollapsedWidth -> 88px ($b4aSidebarCollapsedWidth)
- agentContainer: removido o background navy de 100vh que vazava ACIMA do toolbar
  cinza (a region do header). O navy agora vem do chatWindow/emptyStateOverlay,
  abaixo do toolbar.

Tooltips (title do BrowserMenu = tooltip nativo) mais descritivos:
- Model -> "Select AI model"
- Permissions -> "Permissions — what the agent can do in your database"
- Chat -> "Chat options (clear conversation)"

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…at" vago

Remove o menu "Chat" (que juntava Configure + Clear num icone so, pouco intuitivo)
e coloca dois botoes diretos no toolbar:
- "+" (b4a-add-outline-circle) -> abre o Configure (add/editar/remover modelos). tooltip
  "Add / configure models".
- Clear (b4a-trash-icon) -> limpa a conversa. tooltip "Clear conversation".
Estilo .toolbarAction (icone com padding + hover). clearChat ja guardava o browserMenuRef.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ixeira)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lixeira parecia deletar dados, refresh parecia recarregar. O padrao de chat moderno
para recomecar e o icone de compor/lapis = nova conversa.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lixeira parecia deletar dados, refresh parecia recarregar, lapis parecia editar/voltar.
Texto "Clear" e inequivoco. Tooltip "Clear conversation".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O upgradePrompt (newFeaturesInLatestVersion) aparecia na pagina /apps sugerindo
atualizar o dashboard. Removido o bloco; upgradePrompt fica sempre null.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Rotulo no toolbar com o nome do modelo selecionado (title mostra o model id, ex.
  gpt-4o) — dá pra ver qual está ativo sem abrir o menu.
- selectedAgentModel deixa de ser global e passa a ser por-app (selectedAgentModel_<slug>);
  setDefaultModel respeita a escolha salva do app ou cai no primeiro modelo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tre apps)

O componente Agent é reaproveitado ao navegar entre apps (só o contexto/slug
muda, não há remount), então selectedModel/userAgentConfig/messages ficavam com
os valores do app anterior. Agora detecta a troca de slug em componentDidUpdate
e recarrega a partir do storage do app novo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alStorage

Antes só a API key era env var; a lista de modelos ficava em localStorage
(agentUserConfig_<slug>), o que fazia o display name vazar entre apps. Agora a
config inteira (key em OPENAI_API_KEY + lista em AGENT_MODELS) é env var, então o
backend é a única fonte por-app. Também guarda o render do modelo ativo no
toolbar para só mostrar quando o modelo existe na lista do app atual.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…letar o agent

- Remove o default "My model": o campo de display name começa vazio e, se ficar
  vazio, cai no id do modelo (ex. gpt-4). Assim nada aparece no toolbar antes de
  o usuário salvar um modelo de verdade.
- Adiciona "Delete agent" (danger zone) no dialog: remove os env vars
  OPENAI_API_KEY e AGENT_MODELS, limpa a seleção por-app e volta ao empty state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Em vez de POST /apps/:id/agent no servidor do dashboard (mandando a apiKey no
corpo), o frontend agora chama POST /parse-app/:slug/agent na API back4app via
ParseApp.sendAgentMessage(). A chave OpenAI é lida da env var do app no backend;
o browser não envia mais segredo. O agent server-side é stateless, então o
histórico recente é enviado a cada request. validateModelConfig não exige mais
apiKey no cliente.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Em vez de campo livre pro id do modelo, um dropdown com modelos OpenAI comuns
(gpt-4o, o3, gpt-5, ...) + opção "Custom…" que revela um campo de texto pra
digitar qualquer id (ex. release nova). Evita typo e modelo inexistente sem
travar quem quer um modelo fora da lista. O flag `custom` é só de UI (não é
persistido); Save continua exigindo um model id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O agent deixa de rodar na API compartilhada e passa a rodar dentro do container
do app do cliente, como uma Cloud Function (dashboardAgent). Assim escala com os
recursos do próprio app e a chave nunca sai do container.

- Novo cloud/dashboard-agent/index.js (dashboard-agent.cloud.js): loop OpenAI +
  tools via Parse SDK (useMasterKey local), lê OPENAI_API_KEY/AGENT_MODELS do env,
  exige master key. Importado como texto cru (webpack ?raw / asset/source).
- agentCloudProvisioning.js: injeta/atualiza o arquivo gerenciado (marcador
  @back4app-dashboard-agent) e o require no main.js sem sobrescrever código do
  cliente; aborta com erro claro em colisão de nome; remove no delete.
- ParseApp.getCloudCode/saveCloudCode; saveAgentConfig instala o cloud code ao
  salvar (colisão aborta antes de qualquer write), deleteAgentConfig remove.
- Dialog mostra aviso explícito de que salvar instala Cloud Code e redeploya.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le fallback

Parse.Cloud.httpRequest was removed in Parse Server 6+. HTTP now uses global
fetch (Node 18+) with a fallback to Node's built-in https module, so the Cloud
Function also runs on Node 14 (fetch/AbortController are guarded and unused
there). Clearer network/timeout error message.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…confusion

The agent was inventing app IDs / server URLs and telling users it lacked the
master key. Now the proxy passes the real app context (appId, appName,
dashboardAPI serverURL) into the function, which injects it into the system
prompt as authoritative values. Added instructions: DB access is already granted
via tools (master key handled server-side) — never ask for it, never fabricate
IDs/URLs/schema, and call getSchema/queryClass to answer instead of guessing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
charles-ramos and others added 30 commits August 24, 2026 16:58
The homolog build still saw ts-invariant@0.4.4 (no setVerbosity) — the npm
`overrides` field isn't reliably honored across environments/npm versions.
Declare ts-invariant@^0.10.3 as a DIRECT dependency instead (portable: forces
0.10.3 to the top level on any npm; parse-server's old apollo chain gets a nested
0.4.4). Removed the conflicting override. Also hardcode the back4app2 client URL
(dropped process.env to avoid the DefinePlugin conflict).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… button

- renderContent() instead of render() so DashboardView keeps the sidebar/navbar
  (overriding render() bypassed the whole dashboard shell).
- Use this.context.applicationId (ParseApp stores the appId there) — fixes
  "App context not available" and the currentAppId === appId match.
- Empty state now offers a "Create agent" button when the app has no V3 agent:
  createAgent() calls sdk.createAgent(name,'V3') + setAgentCurrentApp(id, appId),
  then reloads the chat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The back4app2 navbar provides the shared connect.sid session the agent SDK
authenticates with — it must be mounted. It had been left commented out as a
local workaround and got carried into the AgentV3 route commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- parseAgentContent(): strip the streamed ```agent-progress``` fences (and
  tool-call/tool-result/app-info fences + legacy "Using tool:" / "Done." lines),
  extract the events, and render only the clean text — fixes the broken task
  layout (raw JSON + empty Monaco blocks). While a message is in progress, show a
  compact task row (spinner + stage · tool · filePath) from the latest event.
- Hyphen-safe code-fence language regex.
- Delete agent: toolbar action → sdk.deleteAgent(agent.id) (with confirm) →
  resets to the empty/create state. (Create was already added.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The full-screen empty-state overlay (position:fixed) was covering the chat input
whenever there were no messages — including right after creating an agent. Now
the overlay shows ONLY when there is no agent (create/loading); once an agent
exists, an inline centered hint renders inside the chat window and the input
stays available below it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The parse-dashboard agent is the differentiated "v4" — a reduced, app-scoped
agent segregated from the full v3/v5 flavors. findAgents/createAgent now use a
single AGENT_FLAVOR constant so the backend flavor flips in one line. Kept at
'V3' for now (the chat works against real V3 agents); switch to 'V4' once the
segregated v4 flavor lands in back4app2 + the Python agent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The back4app2 v4 flavor (AgentFlavor 'V4' + flavor column) and the Python agent
v4 image are live, so the dashboard now creates/queries V4 agents. New agents
created from the dashboard are persisted with flavor=V4; existing agents remain
V3 (backfilled).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…agent

Toolbar "API key" action opens a dialog to set the agent's own LLM keys
(sdk.setAgentLLMCredentials). Blank fields keep the current key; keys are sent to
the encrypted backend store and never shown back — only hasOpenaiApiKey/
hasAnthropicApiKey booleans are read to indicate a key is set.

NOTE: needs @back4app2/sdk republished with setAgentLLMCredentials + the has*
query fields, and the version bumped here, before it works at runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The published SDK now exposes setAgentLLMCredentials + the agent flavor/has*
fields, so the BYOK "API key" dialog works at runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Invert the BYOK flow: "Create agent" now opens the credentials dialog
FIRST, then creates the agent with the key already set. On a BYOK-only
plan the key is what makes the agent usable, so creating first and asking
after left the agent created-but-useless. The key stays optional (blank =
platform default); the toolbar "API key" action still edits it later.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the first message launches the container, the chat showed only bare
typing dots — it looked like nothing happened until the agent suddenly
became available. Use the ChatMessage status: INITIALIZING renders
"Starting the agent…", INITIALIZED renders "Agent ready — thinking…".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The LLM key/provider is fixed for an agent's life (1 agent : 1 app, no
reconfigure — switching OpenAI<->Anthropic means a new container = a new
agent). Editing the key in place was misleading, so drop it:

- "New agent": destructive — deletes the agent + conversation and
  provisions a fresh one, optionally with a new key. The ONLY way to
  switch the key/provider. Dialog warns the conversation is lost forever.
- "Clear key": non-destructive — clears the BYOK key (back to the platform
  default) and keeps the conversation. Only shown when a key is set.

No "clear chat": the conversation is server-side and the agent's context
lives in its container, so a display-only clear would be a lie — "New
agent" is the honest fresh start.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dialog now has a provider toggle (OpenAI | Anthropic) + a single key
field, instead of two key fields. An agent uses ONE provider, so only the
chosen provider's key is sent (the other is explicitly empty). Matches the
1-agent-1-provider model and avoids the "both keys" confusion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Swap the OpenAI|Anthropic toggle for the dashboard's standard Dropdown +
Option (same pattern as the old AgentConfigDialog) — reads better in the
dialog and is theme-consistent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Delete and Clear-key now confirm with the dashboard's B4aModal (DANGER for
delete, DEFAULT for clear) — the same danger dialog the Cloud Code section
uses — instead of a native browser alert. Modal is held in state.modal and
rendered inline; subtitleModal styling mirrors Cloud Code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
For now V4 has no platform-key option: a key is required to create an agent.
- Dialog: the key field is required (submit disabled until filled); copy no
  longer mentions a platform default.
- Toolbar: drop "Clear key" (nothing to fall back to).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the text toolbar links with icon buttons (refresh = New agent,
delete = Delete agent) with title tooltips, matching the Browser toolbar
pattern. Cleaner toolbar; the tooltip carries the explanation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Container-startup failures arrive as a full Python traceback / log dump.
Extract just the final "SomeError: message" line (e.g. "No LLM provider
configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY.") for the chat error,
falling back to the first line. Dashboard-only; no backend change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sending a message while the container is still starting returned "agent has
not initialized". Disable the input (and show "Preparing your agent…") while
the agent status is INITIALIZING/INITIALIZED/LAUNCHING, and poll getAgent
until it reaches READY, then un-gate. Poll is cleared on unmount/app switch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The textarea was disabled during the in-flight send, dropping focus, so the
user had to click back in before typing the next message. Keep the textarea
enabled while sending (only the Send button disables) and refocus it after
the send resolves.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cut the redundant "fixed / to switch create a new agent" (it's the new-agent
dialog itself) and the "(required)" (the field already says Required). Down
to one tight line per mode.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The borderless button read as flat/not-a-button. Reserve a transparent
border in the base (no size jump) and color it when enabled (brighter on
hover); disabled stays borderless.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dashboard agent is the V4 flavor, but the file/class/comments still said
V3. Rename AgentV3.react.js -> AgentV4.react.js, the class AgentV3 -> AgentV4,
and update the import + comments. No behavior change (branch name kept).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…vor)

Follow-up to the file rename: class AgentV3 -> AgentV4, the Dashboard import
path, and the V3-mentioning comments in AgentV4.react.js and back4app2Client.js.
No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a Model dropdown (curated per provider + "Custom…" free-text) to the
creation/new-agent dialog; provider switch resets the model. Model is
required (Create disabled until key AND model are set) and passed to
setAgentLLMCredentials(model). Provider lists: OpenAI = gpt-5.3-codex/5.5/
5.6-terra; Anthropic = claude-sonnet-5/opus-4-8/sonnet-4-6.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The published SDK now carries the `model` arg on setAgentLLMCredentials and
Agent.llmModel, so the create dialog's model choice reaches the backend.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
back4app2Client.js hardcoded the GraphQL endpoints to
api.containers-homolog.back4app.com, so the Agent tab always talked to
homolog regardless of environment. Locally that fails auth outright: the
SDK authenticates with the shared `connect.sid` cookie, which is scoped to
localhost and never reaches a .back4app.com host, surfacing in the UI as
"Couldn't load the agent: unexpected error".

b4aSettings.CONTAINERS_API_PATH already carries the right URL per
environment (dev.json -> http://localhost:4040) and is what src/lib/back4app2.js
uses. Use it here too, and derive the ws URL from the http one so the two
can never drift apart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B4aBadge positions itself with `float: right`, which works in the default
section header (`display: block`) but silently does nothing once the section
is active: `.active .section_header` switches to `display: flex`, and floats
do not apply to flex items. The badge collapsed against the label with no
gap the moment the section was clicked.

`margin-left: auto` is the flex equivalent of the float. The badge's 5px top
offset also goes, since `align-items: center` already handles the vertical
alignment here.

B4aBadge's class name is hashed by CSS Modules and cannot be referenced from
this stylesheet, so the rule matches the last span only when it is not the
only one — the label and the badge are both spans and the icon is an svg, so
that is exactly "a badge follows the label". With no badge, or a collapsed
sidebar where the label span is not rendered, nothing matches and the label
is never pushed right.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…adge

The product had three agents whose names barely differed: `agent` (v3),
`agents` (v5) and this one. "Backend Agent" names it by the surface the user
is actually on when they use it — the Backend dashboard — which is the axis
they can tell apart without knowing about flavors or sandboxes.

Also renames the user-facing strings that said "AI Agent": the empty states,
the key dialog titles, and the Cloud Code collision errors.

The sidebar's `section` prop is not cosmetic — B4aSidebar decides the active
item with `name === section`, so the label and the Toolbar section have to
move together or the item stops highlighting. The Toolbar subsection drops
out entirely: "Backend Agent / AI Agent" was redundant, and single-page
sections (Config, Cloud Code) already render without one.

The icon becomes "AI" drawn as filled paths. Not `<text>`, which would depend
on a font resolving inside the sprite, and not strokes: SvgPrepPlugin builds
the sprite with `noFill: true` so icons inherit the color the Icon component
sets as `fill`, and a stroked icon would keep its own color instead.

`b4a-agent` stays — the AI Tools menu still uses it for the containers agent.
So does the `/agent` route and the internal V4 flavor name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant