Skip to content

Fix/base init test checkout path#20

Open
cluster2600 wants to merge 12 commits into
ai-swiss:mainfrom
cluster2600:fix/base-init-test-checkout-path
Open

Fix/base init test checkout path#20
cluster2600 wants to merge 12 commits into
ai-swiss:mainfrom
cluster2600:fix/base-init-test-checkout-path

Conversation

@cluster2600

Copy link
Copy Markdown

Summary

Type

  • Fix
  • Feature
  • Docs
  • Refactor / tests / tooling

Checklist

  • npm test green (core + packages)
  • npm run typecheck clean
  • node tools/base.mjs validate --root . → "BASE valide."
  • node tools/base.mjs route-test --root . stable (and the example fixtures, if routing changed)
  • Derived artifacts regenerated if needed (npm run index, base build --write)
  • MCP touched? cd mcp && npm run build && npm test (the build runs tsc; vitest alone does not type-check)
  • Studio touched? cd tools/studio/ui && npm test && npm run build (and npm run e2e for user flows)
  • No em-dashes in French public content; specs/docs updated if behaviour changed
  • A test accompanies any change to verifiable behaviour

cluster2600 and others added 12 commits June 28, 2026 12:14
createMoaModel wraps N proposer models + 1 aggregator and conforms to the
existing LanguageModel port ({ id, complete, stream? }), so it drops in
anywhere a single model is expected.

Flow (Wang et al. 2024 MoA, the shape Hermes' `moa` provider uses):
proposers answer the same request in parallel with tools stripped (text
drafts only), then the aggregator synthesizes the drafts — folded into the
system message as private guidance — with the original tools intact so
tool-calling still works through it. Usage is summed across all models.

No ground-truth judge exists in chat, so the aggregator LLM is the selector,
matching Hermes' design. Resilient to partial proposer failures; throws only
if every proposer fails.

Tested with faux/stub models (no API keys): synthesis, tool-stripping,
partial-failure resilience, usage summation, config validation, streaming.
feat(base-llm): Mixture-of-Agents meta-model
createTriumviratModel implements the inference-time architecture of Sakana
Fugu / TRINITY (arXiv:2512.04695). The name nods to the three roles it
coordinates. Each turn a coordinator picks a model from a swappable pool and
assigns it a role (Thinker plans, Worker executes and is the only role given
tools, Verifier judges the draft and gates termination), looping until
accepted or a turn budget hits.

TRINITY's contribution is a CMA-ES-trained 0.6B coordinator, which can't be
reproduced as a PR, so the default coordinator is prompted (an LLM choosing
model+role+stop) with a deterministic Thinker->Worker->Verifier fallback.
The coordinator.decide seam lets a heuristic or trained coordinator drop in
later with no API change. Conforms to the LanguageModel port, sums usage,
threads the abort signal, recovers from failed role turns.

Tested with stub models (no keys): happy path, reject-then-fix feedback,
budget exhaustion, tool routing, usage summation, prompted-coordinator JSON
path, deterministic fallback, role-failure recovery, abort, config validation.
Add an `ensembles` block to .ai/studio.settings.json so MoA and Triumvirat
are configurable without code. resolveModel checks ensembles before the
provider path: an ensemble entry names a type (moa | triumvirat) plus member
refs, and each member resolves through the existing <provider>/<model>
registry, so the ensemble name then works anywhere a model ref does.

Bad config (missing aggregator/pool, unknown type, unknown provider member)
fails with a clear BAD_REQUEST. Tests cover both ensemble types, a plain
provider ref regression, and each error path. Docs with a resolution diagram.
createLangfuseModel wraps any base-llm model and conforms to the same port
({ id, complete, stream? }), so it composes over a single adapter, a MoA, or
a Triumvirat. Every call is traced to Langfuse: input, output, token usage,
latency, and errors.

Zero new dependencies: no Langfuse SDK, just native fetch against the public
ingestion API (POST /api/public/ingestion, HTTP Basic auth). Ingestion is
fire-and-forget so it never adds latency; flush() drains in-flight sends.
A telemetry failure never breaks the wrapped call (routed to onError).

Keys default to env LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY; self-hosted
via LANGFUSE_HOST. Tested with a fake fetch (no network): trace+generation
emission, usage mapping, error traces, ingestion-failure resilience, env
keys, streaming capture, config validation. Docs with a mermaid sequence
diagram.
- packages/base-llm/README.md: a Composition section linking the MoA,
  Triumvirat, ensembles-settings and Langfuse docs so they are discoverable
  from the package root.
- docs/reference/orchestration-et-supervision.md: a French reference page
  (authoritative) for the docs site, plus its English mirror under docs/en.
  Present-tense, em-dash-free, lexicon/translation/tree gates green.

Makes the new capabilities visible on the default branch and in the rendered
manual once merged.
Orchestration + monitoring: Triumvirat, ensembles, Langfuse, docs
… pass

- Register de (Deutsch) and it (Italiano) locales in the docs-site config.
- Translate all 74 French reference pages to German and Italian under
  docs/de/ and docs/it/, each a body-only mirror with a fr-synced hash that
  matches its French source (the gate that keeps translations from drifting).
- Add mermaid diagrams to the French pages that genuinely describe a flow,
  decision tree, or lifecycle (routing voies, provider selection, adoption,
  expertise lifecycle, ...), mirrored into en/de/it.

All doc gates pass: em-dash, statusless, punctuation, lexicon, translations,
tree. German targets the Swiss German-speaking audience; Italian is natural.
Machine-assisted, so a native review pass is worthwhile before publishing.
docs(i18n): German + Italian translations of all 74 pages + mermaid
The CLI init test asserted the framework directory's name
(endsWith('/base') or includes('Repositories')), which encoded the
maintainer's local checkout and failed on any clone in a differently
named directory (forks, CI scratch dirs, base-repo, ...).

base init is correct: it records framework_dir as the framework root
resolved from the CLI's own location. Assert that invariant instead:
framework_dir == path.dirname(path.dirname(cliPath)).

Full suite now 866/866 (this was the only failing test). Closes #8.
@cluster2600 cluster2600 requested a review from cbardyn as a code owner June 28, 2026 20:00
@cbardyn

cbardyn commented Jul 2, 2026

Copy link
Copy Markdown

Bonjour Maxime, et merci pour ce correctif.

Sur le fond, la correction vise juste: l'assertion actuelle (framework_dir.endsWith('/base') || includes('Repositories')) encode le dossier de checkout du mainteneur et casse sur tout autre clone ou répertoire de CI; l'invariant que vous proposez (framework_dir === dirname(dirname(cliPath))) est le bon, c'est exactement ce que base init garantit. Très bien vu.

Un élément nouveau depuis votre envoi, à intégrer au correctif: en 1.1.0, framework_dir est désormais enregistré en séparateurs POSIX sur tout système (a/b, jamais a\b), et la CI comporte un contrôle requis sous Windows qui exécute précisément tests/base-cli-init.test.mjs. L'égalité stricte avec path.dirname(path.dirname(cliPath)) échouerait donc sous Windows (séparateurs natifs à droite, POSIX à gauche): il faudra normaliser le côté droit, par exemple path.dirname(path.dirname(cliPath)).split(path.sep).join("/"). Ainsi l'assertion devient portable sur les trois OS que la CI couvre.

Le reste du cadrage tient toujours: la branche n'est pas partie d'un main à jour mais empilée au-dessus de vos #17 (orchestration) et #18 (traductions), d'où 228 fichiers et plus de 14 000 lignes pour un correctif qui en fait trois, et une duplication de deux PR déjà ouvertes; nous préférons revoir ces travaux là où ils vivent. Pourriez-vous, pour cette PR:

  • repartir d'une branche fraîche sur le main courant et n'y garder que le commit du correctif (avec l'ajustement POSIX ci-dessus);
  • signer les commits (git rebase --signoff): le contrôle DCO les attend, aucun n'est signé pour l'instant;
  • retirer le Closes #8 du message: l'issue Bump the studio-dependencies group in /tools/studio/ui with 9 updates #8 concerne une mise à jour Dependabot du Studio, sans rapport avec ce test.

Ainsi scopée, rebasée et signée, la correction passera sans friction. Merci encore, et bravo pour le reste du travail: on en reparle dans #17 et #18.

@cbardyn cbardyn added the en attente du contributeur Réponse postée; la prochaine action est côté contributeur (rebase, DCO, discussion) label Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

en attente du contributeur Réponse postée; la prochaine action est côté contributeur (rebase, DCO, discussion)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants