Skip to content

Pride deploy - #27

Merged
selvaebi merged 13 commits into
mainfrom
pride-deploy
Sep 15, 2026
Merged

selvaebi merged 13 commits into
mainfrom
pride-deploy

Conversation

@selvaebi

Copy link
Copy Markdown
Collaborator

No description provided.

selvaebi and others added 12 commits September 6, 2026 23:33
…wiring

Adds a Dockerfile (repo-root build context, needed for sibling
sdrf-proteomics/ cell-line tables), GitHub Actions build-and-push to GHCR,
and plain kubectl manifests (namespace/configmap/secret/deployment/service/
ingress). LLM
config is env-driven via the ConfigMap/Secret, no
rebuild needed to change it. Also adds ROOT_PATH support to FastAPI for the
path-prefixed ingress.
The k8s Deployment forces runAsUser/runAsGroup/fsGroup: 1000, but the
Dockerfile created appuser with an arbitrary auto-assigned system UID, so
chown -R appuser:appuser /app didn't match the runtime UID. The
docker-entrypoint.sh index-build step then failed with PermissionError
writing to backend/data/spec_index/ (confirmed in pod logs after the first
deploy to hh-11 -- specIndexReady stayed false, chunkCount 0).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
Add LLM_AUTH_HEADER so LlmClient can send X-API-Key instead of
Authorization: Bearer, for OpenAI-compatible gateways that reserve the
Authorization header for a different credential type. Defaults to
Authorization: Bearer, unchanged for every other provider.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
…client

Found by replaying the real agent.py request against pride-llm-api's gateway:
vLLM's chat template rejects a messages array with more than one system-role
entry, or a system message anywhere but the first position ("System message
must be at the beginning"). agent.py built 3-6 separate system messages
(prompt, wizard context, step focus, skill, evidence, accession) plus a later
one injected mid-conversation when tool rounds are exhausted.

Fix: consolidate all leading system content into one message; the
mid-conversation "wrap up" reminder becomes a user-role message instead
(safe at any position).

Also: the failure above came back as HTTP 200 with the error embedded in an
SSE chunk, not a 4xx -- client.py only checked for a "choices" key, so it
silently dropped the error chunk and produced an empty response with no
error surfaced anywhere. Now raises LlmError with the upstream detail.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
…sting

Adds an additional k8s deployment path for the Angular frontend, alongside
the existing GitHub Pages and SSH-to-server deployments (untouched). Served
at /pride/services/sdrf-editor -- built with --base-href baked in since
Angular's client-side router ties routing to <base href>, unlike the
backend's ingress-rewrite approach.

backend-build-and-push.yml and frontend-build-and-push.yml now also trigger
on push to this branch (pride-deploy), tagging images :pride for hh-11
testing without touching :latest (which only moves on a push to main).
Both k8s deployments reference :pride accordingly.

No real endpoint values or secrets are in this branch: configmap.yaml keeps
the generic placeholder LLM_BASE_URL, and the actual pride-llm-api address
plus all API keys are applied straight to the cluster via kubectl from
gitignored, untracked local files (secret.yaml) -- never committed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
Nothing in assistantUrlCandidates() could find the hh-11 backend:
location.origin (tried first) assumes the backend is at the origin root
(/api/health), but it's served under /pride/services/sdrf-assistant; the
existing HOSTED_ASSISTANT_ORIGINS entries are for the sdrf.site deployment;
and the compiled environment.assistantBaseUrl is the dev default
(http://localhost:8000, no production environment file replaces it). Net
effect: the assistant panel never appeared on the hh-11-deployed frontend.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
This model writes its reasoning inline in content (confirmed directly
against the deployed gateway) rather than a separate field, so the panel was
showing hundreds of tokens of chain-of-thought before the actual answer.

SYSTEM_PROMPT now instructs the model to wrap reasoning in <think>...</think>
before the final answer. Empirically (tested directly against the model) it
reliably emits the closing </think> but usually omits the opening <think> --
it treats generation as already inside the block. ThinkingSplitter (new)
accounts for this: each round is assumed to start "thinking" by default,
suppressing content until </think>; if </think> never appears at all (model
answered directly), flush() releases everything buffered so that text isn't
silently lost.

agent.py's two streaming rounds now emit one "Thinking..." status event per
round instead of streaming the reasoning text itself -- only content after
</think> streams as visible tokens. This also keeps the SSE connection alive
throughout (avoiding the idle-timeout on slow responses discussed earlier)
without exposing the reasoning to the user.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
Builds started failing ("permission_denied: The requested installation does
not exist") once this repo moved orgs -- GITHUB_TOKEN's package-write scope
follows the repo's current owner, but IMAGE_NAME was hardcoded to the old
bigbio/ path. Compute it from github.repository instead (lowercased in
bash -- GHCR/Docker image names must be lowercase, GitHub Actions
expressions have no toLower(), and this org, "PRIDE-Archive", isn't already
lowercase). Updates the k8s deployment.yaml image references and READMEs to
match (ghcr.io/pride-archive/...).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
Found by direct testing against the deployed model: it can spiral into
repetitive reasoning for thousands of tokens before ever emitting </think>,
getting cut off by the token cap while still "thinking." Since
ThinkingSplitter's flush() has to release unclosed content rather than
silently dropping a genuine no-think direct answer, that runaway text was
landing on the user as-is -- the exact opposite of hiding chain-of-thought.

ThinkingSplitter now exposes saw_close_tag so a caller can tell "answered
directly" (flush() text is legitimate, any length) apart from "still
mid-thought when the round ended" (flush() text is raw reasoning). agent.py
replaces the latter with a short fallback message when it's implausibly long
for a direct answer (>800 chars) -- text that already streamed live after a
genuine </think> is never touched by this, whatever its length.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4DK78AWBWKoFPoQ1mNJqf
Build backend/frontend images and push to GitLab Container Registry,
deploy to hh-11 via kubectl using GitLab CI/CD variables for secrets
and kubeconfig instead of a manually-applied local secret.yaml.
Layout follows pride-archive-api's .gitlab-ci.yml/.kubernetes.yml
convention: one envsubst-templated kubernetes.yml per app, namespace
and imagePullSecret created imperatively by the pipeline, ingress
applied manually/once outside CI.

Also fills in the backend ConfigMap's real pride-llm-api values
(LLM_AUTH_HEADER, LLM_MODEL) and moves LLM_BASE_URL/EMBEDDING_BASE_URL
to GitLab CI/CD variables rather than committed values -- both point
at internal hh-44 worker hostnames, not something to put in a repo
that's mirrored to public GitHub.
Replaces Chinese strings in the wizard AI assistant components
(tool-call-list, wizard-ai-panel) and translates USER.md and the
wizard mobile/AI implementation notes so the whole project is
English-only.
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 08eabb81-d347-45a3-84fb-957f5f8c793c


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The workflow ran the plain \`pytest\` console script, which doesn't add
the cwd to sys.path, so \`import app\` failed in CI even though tests
pass locally with \`python -m pytest\` (as README.md documents).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011RMFv4AaKDNPeCQ9NFLCc3
@selvaebi
selvaebi merged commit 03bda45 into main Sep 15, 2026
2 checks passed
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.

2 participants