ACP · Integration

Integrationsunterlagen · v0.1.0 · M1 abgeschlossen Integration material · v0.1.0 · M1 complete

Was die Plattform leistet What the platform does

ACP ist eine mandantenfähige Plattform für agentische Kundenkommunikation: Sprache und Chat, Deutsch und Englisch, Datenhaltung in der EU. Diese Seite beschreibt, was heute tatsächlich im Repository steht. Jede Zahl unten ist im Code nachprüfbar, und was fehlt, steht am Ende der Seite. ACP is a multi-tenant platform for agentic customer conversations: voice and chat, German and English, EU data residency. This page describes what is actually in the repository today. Every figure below is checkable against the code, and what is missing is listed at the end of the page.

Im ÜberblickAt a glance

1466
Tests, grün und offline — ohne eine einzige Zugangsdatei tests, green and offline — with zero credentials
12
Protocols in contracts.py — die austauschbare Naht Protocols in contracts.py — the swappable seam
13
REST-Routen unter /v1, dazu ein WebSocket-Stream REST routes under /v1, plus one WebSocket stream
7
Sprachen im Language-Kontrakt, jede mit Eröffnungsskript languages in the Language contract, each with an opening script

Nachgezählt am Repository, nicht geschätzt: pytest -m "not live" meldet 840 bestandene Tests; contracts.py deklariert zwölf Protocols; build_v1_router() registriert dreizehn HTTP-Routen und einen WebSocket; das Language-Enum hat sieben Werte (DE, EN, IT, CS, SK, PL, FR) und das Compliance-Gate hält für jeden ein vollständiges Eröffnungsskript bereit. Die Konsolen und das Kunden-Widget selbst sind zweisprachig (DE/EN). Counted from the repository, not estimated: pytest -m "not live" reports 840 passing tests; contracts.py declares twelve Protocols; build_v1_router() registers thirteen HTTP routes and one WebSocket; the Language enum has seven members (DE, EN, IT, CS, SK, PL, FR) and the compliance gate carries a complete opening script for each. The consoles and the customer widget themselves ship DE + EN.

Die eine IdeeThe one idea

Die Naht besitzen, die Motoren mieten Own the seam, rent the engines

Jede Fähigkeit, die man kaufen kann — Spracherkennung, Sprachsynthese, das Sprachmodell, der Medientransport — liegt hinter einem Protocol in src/acp/contracts.py. Die Schichten, die dem Produkt gehören (Orchestrator, Compliance, Voice-Pipeline, ERP-Repository, Konsolen), importieren kein einziges Anbieter-SDK. Every capability that can be bought — speech recognition, speech synthesis, the language model, the media transport — sits behind a Protocol in src/acp/contracts.py. The layers the product owns (orchestrator, compliance, voice pipeline, ERP repository, consoles) import zero vendor SDKs.

Anbieterbibliotheken werden lazy importiert, innerhalb der Methode, die sie benutzt. Deshalb importiert, startet und testet die gesamte Plattform ohne Zugangsdaten und ohne installierte optionale Pakete — und deshalb ist ein Anbieterwechsel eine Konfigurationsänderung, kein Code-Eingriff. Vendor libraries are imported lazily, inside the method that uses them. That is why the whole platform imports, runs and tests with no credentials and no optional packages installed — and why swapping a provider is a configuration change, not a code change.

Konfiguration wird aus einem expliziten Mapping aufgelöst (Settings.from_env(mapping)), nicht aus der Prozessumgebung. Ein TenantContext trägt die eingefrorenen Settings eines Mandanten durch Graph, Router, Gate, Odoo-Client und alle Adapter-Fabriken. Folge: zwei Mandanten können in einem Prozess unterschiedliche Anbieter fahren — ohne os.environ zu mutieren. Configuration is resolved from an explicit mapping (Settings.from_env(mapping)), not read from the process environment. A TenantContext carries one tenant's frozen settings through the graph, router, gate, Odoo client and every adapter factory. The consequence: two tenants can run different providers inside one process — with no os.environ mutation.

FähigkeitCapability Protocol Adapter im RepoAdapters in the repo Umschalten überSwapped via
SprachmodellLanguage model LLMClient · LLMRouter claude · openai · gemini · grok · oss · mock RouterPolicy · ACP_CONFIDENTIAL_FRONTIER
SpracherkennungSpeech to text STTEngine speechmatics · parakeet · mock ACP_STT
SprachsyntheseText to speech TTSEngine azure · elevenlabs · cartesia · fish · piper · mock ACP_TTS
MedientransportMedia transport TransportSession livekit · mock ACP_TRANSPORT
Sprache-zu-SpracheSpeech to speech RealtimeVoiceSession openai_realtime · gemini_live · mock ACP_VOICE_MODE · ACP_REALTIME
ERPERP OdooRepository Odoo JSON-RPC · In-Memory ODOO_URL · ODOO_DB · ODOO_USER · ODOO_API_KEY
WissensindexKnowledge index KnowledgeIndex deterministischer Offline-Embedder (Standard) deterministic offline embedder (default) Protocol-Implementierung Protocol implementation

Jede Fähigkeit hat einen Mock, und der Mock ist überall der Standard. Ein falsch gesetzter Engine-Name für STT oder TTS fällt mit einer Warnung auf den Mock zurück, statt die Plattform zu stoppen; ein unbekannter Name wird abgelehnt. Every capability has a mock, and the mock is the default everywhere. A selected STT or TTS engine whose credential is missing falls back to the mock with a warning rather than crashing the platform; an unknown name is rejected outright.

Kanäle · Sprachen · DatenraumChannels · languages · residency

Sprache und Chat, und die Sensitivität entscheidet, wohin es geht Voice and chat, and sensitivity decides where the turn may go

Der Sprachpfad läuft wahlweise kaskadiert (STT → LLM → TTS) oder als Realtime-Sprache-zu-Sprache-Sitzung; beides steht hinter demselben Kontrakt und wird pro Anruf gewählt. Chat läuft über dasselbe Gehirn, nicht über ein zweites System. Die Region ist voreingestellt auf eu-central-1 (Frankfurt). The voice path runs either cascaded (STT → LLM → TTS) or as a realtime speech-to-speech session; both sit behind the same contract and are chosen per call. Chat runs on the same brain, not on a second system. Region defaults to eu-central-1 (Frankfurt).

Die Sensitivität eines Gesprächs ist ein hartes Tor, keine Präferenz. Geschwindigkeit (schnell für Live-Sprachzüge, stark für asynchrones Nachdenken) optimiert erst innerhalb dessen, was die Sensitivität erlaubt. Einen Rückfall über die Grenze hinweg gibt es nicht: eine sensible Bahn, die on-prem nicht bedient werden kann, scheitert — sie leckt nicht zu einer Frontier-API. A conversation's sensitivity is a hard gate, not a preference. Speed (fast for live voice turns, strong for asynchronous reasoning) optimises only within what sensitivity allows. There is no cross-boundary fallback: a sensitive lane that cannot be served on-prem fails rather than leaking to a frontier API.

SensitivitätSensitivity Was das heißtWhat it means Wohin der Zug gehtWhere the turn goes
PUBLIC keine Kundendatenno customer data Frontier-Anbieter, von der Geschwindigkeit gewähltfrontier provider, chosen by speed
INTERNAL Geschäftsdaten, keine personenbezogenen Datenbusiness data, no personal data Frontier-Anbieter, von der Geschwindigkeit gewähltfrontier provider, chosen by speed
CONFIDENTIAL benannter Kunde mit Kontaktdaten oder kommerziellen Konditionennamed customer with contact data or commercial terms on-prem, außer ACP_CONFIDENTIAL_FRONTIER ist gesetzt — das erklärt ausdrücklich eine EU-Region mit Zero-Retention-Haltung on-prem, unless ACP_CONFIDENTIAL_FRONTIER is set — which explicitly declares an EU-region, zero-retention posture
RESTRICTED besondere Kategorien oder vertragliches Exportverbotspecial-category data or a contractual no-export clause immer on-prem; die Stimme wird zwangsweise kaskadiert gefahren (Parakeet-STT, Piper-TTS), weil Cloud-Sprache-zu-Sprache diese Bahn nicht bedienen kann always on-prem; the voice stack is forced to cascaded (Parakeet STT, Piper TTS), because cloud speech-to-speech cannot serve this lane

MandantentrennungMulti-tenancy

Getrennt wird an der Datenschicht, nicht in der Anfrage Isolation is enforced at the data layer, never from the request

DimensionDimension MechanismusMechanism
KonfigurationConfiguration pro Mandant aufgelöste, eingefrorene Settingsper-tenant, frozen Settings
Routing und RegionRouting and region eigene RouterPolicy und eigene Region je Mandanta per-tenant RouterPolicy and region
GeheimnisseSecrets aus einem expliziten Mapping aufgelöst, nie aus os.environresolved from an explicit mapping, never from os.environ
MotorenEngines jede Adapter-Fabrik nimmt settings= entgegenevery adapter factory takes settings=
WissenKnowledge eigenes Git-Verzeichnis unter dem Mandanten-Rootits own Git directory under the tenant root
TranskripteTranscripts TranscriptStore wird für einen Mandanten gebaut — es gibt kein Mandanten-Argument zum VergessenTranscriptStore is constructed for a tenant — there is no per-call tenant argument to forget
Live-ZustandLive state Hub-Registry je Mandant; der prozessglobale, mandantenblinde Hub war der Befund einer feindlichen Prüfung und ist geschlossena per-tenant hub registry; the process-global, tenant-blind hub was a hostile-review finding and is closed
MetrikenMetrics Label tenant; Gesprächs-IDs werden nie zu Labelsa tenant label; conversation ids never become labels
WebhooksWebhooks eigene Endpunkte und eigene Signaturgeheimnisse je Mandantper-tenant endpoints and per-tenant signing secrets

Mensch in der SchleifeHuman in the loop

Agenten schlagen vor, Menschen entscheiden Agents propose, humans decide

WissenKnowledge

Markdown in Git ist die Quelle der Wahrheit — alles andere ist abgeleitet Markdown in Git is the source of truth — everything else is derived

Veröffentlichen ist ein Commit. Der semantische Index und der kompilierte Prompt sind Ableitungen, die jederzeit neu gebaut werden können; geht der Index verloren, geht nichts verloren. Ein Mensch kann die Wahrheit lesen, diffen und reviewen, ohne ein Werkzeug zu öffnen. Publishing is a commit. The semantic index and the compiled prompt are derived artefacts that can be rebuilt at any time; losing the index loses nothing. A human can read, diff and review the source of truth without opening a tool.

  1. AufnehmenIngest
    normalisieren und das Original samt Herkunft behaltennormalise, and keep the original with its provenance
  2. StrukturierenStructure
    nach Überschriften trennen, nie nach Zeichenzahl — ein Schnitt mitten in einer Einschränkung erzeugt eine Aussage, die schlicht falsch istsplit by heading, never by character count — a boundary mid-qualifier produces a fact that is simply wrong
  3. KlassifizierenClassify
    Typ, Kategorie, Sprache, Publikum, Autoritättype, category, language, audience, authority
  4. VerifizierenVerify
    jede Behauptung im Quelltext verankern; jede Zahl muss wörtlich vorkommen. Der Verifizierer ist bewusst lexikalisch und kein Modell — ein Modell, das die Ausgabe eines Modells prüft, teilt dessen Fehlermodi.ground every claim in the source text; every figure must appear verbatim. The verifier is deliberately lexical, not model-based — a model checking a model's output shares its failure modes.
  5. FreigebenApprove
    ein Mensch, neben der Quelle. Absichtlich nicht automatisch.a human, beside the source. Deliberately not automatic.
  6. VeröffentlichenPublish
    ein Commit, ein Neuaufbau — hinter dem Golden-Gateone commit, one rebuild — behind the Golden gate
98%
Golden-Gate-Toleranz: fällt ein Build unter 98 % des letzten bestandenen Ergebnisses, wird die Registry zurückgerollt und der vorherige Index bleibt live Golden-gate tolerance: if a build scores below 98 % of the last passing result, the registry is rolled back and the previous index stays live
4
Lebenszyklus-Zustände: Entwurf → verifiziert → veröffentlicht → stillgelegt. Der Sprung vom Entwurf direkt zur Veröffentlichung ist unzulässig, und eine Bearbeitung setzt einen veröffentlichten Datensatz zurück auf Entwurf. lifecycle states: draft → verified → published → retired. Jumping from draft straight to published is illegal, and editing a published record re-drafts it.

Das Tor, das zähltThe gate that matters

Zwei Etiketten entscheiden alles, und sie zu verwechseln ist der Fehler, der wehtut. Der Typ sagt, wie ein Datensatz wirkt (Fakt wird abgerufen, Verhalten wird in den Prompt kompiliert, Anleitung wird zum Handbuch, Quelle ist nur Herkunft). Autorität × Publikum sagt, wie er verwendet werden darf. may_be_told_to_customer() ist das eine, testbare Tor: eine Wettbewerbsanalyse ist Kontext, ein Transkript ist ein Signal — und keines von beiden darf einem Kunden als Tatsache gesagt werden, so relevant der Abruf sie auch findet. Vertrauen kommt aus der Quelle, nie aus der Prosa: der Klassifizierer darf das Publikum verengen, aber niemals über das hinaus erweitern, was die Quellenart erlaubt. Das Tor läuft zur Abfragezeit, nicht nur beim Bauen. Two labels decide everything, and confusing them is the failure that hurts. Type says how a record acts (a fact is retrieved, a behaviour is compiled into the prompt, a guide renders to a manual, a source is provenance only). Authority × audience says how it may be used. may_be_told_to_customer() is the single, testable gate: a competitor analysis is context and a transcript is a signal — and neither may be stated to a customer as fact, however relevant retrieval finds them. Trust comes from the source, never from the prose: the classifier may narrow the audience but can never widen it past what the source kind allows. The gate runs at query time, not only at build time.

Regierte SchreibvorgängeGoverned writes

Der Agent ändert keinen ERP-Datensatz — er schlägt ihn vor The agent never mutates an ERP record — it proposes one

RegulatorikCompliance

Die Offenlegung kommt vom Server, damit sie niemand weglassen kann The disclosure comes from the server, so nobody can leave it out

BeobachtbarkeitObservability

800 ms
Zeitbudget für einen Gesprächszug — die Physik natürlicher Sprache. Pro Mandant über ACP_TURN_BUDGET_MS einstellbar; jede Überschreitung wird gezählt und kann als Webhook-Ereignis herausgehen. latency budget for one conversation turn — the physics of natural speech. Configurable per tenant via ACP_TURN_BUDGET_MS; every breach is counted and can leave as a webhook event.

Die Pipeline misst jeden Zug end-to-end und je Stufe, und das Ergebnis wird emittiert, nicht berechnet und weggeworfen — das war ein Prüfbefund. Die Metriken liegen im Prometheus-Textformat unter /metrics, hinter einem Token, das fehlend nicht etwa durchlässt, sondern den Endpunkt schließt. The pipeline measures every turn end-to-end and per stage, and the result is emitted rather than computed and discarded — that was an audit finding. Metrics are exposed in Prometheus text format at /metrics, behind a token whose absence closes the endpoint rather than opening it.

Protokolle sind strukturiert (in Produktion als JSON, eine Zeile ein Objekt), und der Mandant ist an den Kontext gebunden — er steht auf jeder Zeile, statt an jeder Aufrufstelle mitgereicht werden zu müssen. Logs are structured (JSON in production, one object per line), and the tenant is bound into the context — it appears on every line rather than having to be passed at every call site.

MetrikMetric Was sie beantwortetWhat it answers
acp_turn_latency_ms · acp_stage_latency_ms Wie lange dauert ein Zug — insgesamt und je Stufe?How long does a turn take — in total and per stage?
acp_turns_total · acp_turn_budget_breach_total Wie viele Züge, und wie viele davon rissen das Budget?How many turns, and how many of them broke the budget?
acp_tool_failure_total · acp_transcript_write_failure_total Welche Werkzeuge scheiterten, und welche Transkripte konnten nicht geschrieben werden?Which tools raised, and which transcripts could not be persisted?
acp_webhook_delivered_total · acp_webhook_failed_total · acp_webhook_blocked_total Kommen Ereignisse an, und was hat die Egress-Richtlinie abgewiesen?Are events arriving, and what did the egress policy refuse?
acp_golden_gate_pass_total · acp_golden_gate_fail_total Wie viele Wissens-Builds hat das Golden-Gate durchgelassen oder zurückgerollt?How many knowledge builds did the Golden gate pass or roll back?
acp_widget_session_total · acp_widget_refused_total Wie viele Widget-Sitzungen wurden ausgegeben, wie viele wegen Schlüssel oder Origin abgelehnt?How many widget sessions were issued, and how many refused for a bad key or origin?

EhrlichkeitHonesty

Was noch nicht fertig ist What is not done yet

Alles Obenstehende ist heute grün — auf Mocks. Das Folgende ist es nicht, und es steht hier, weil eine Integrationsunterlage, die Lücken verschweigt, beim ersten echten Anruf auffliegt. Everything above is green today — on mocks. The following is not, and it is listed here because integration material that hides its gaps is found out on the first real call.

LückeGap Was das für eine Integration bedeutetWhat it means for an integration FälligDue
H2 — LiveKit-Token wird unauthentifiziert ausgestelltH2 — LiveKit token minting is unauthenticated Offener Prüfbefund. Er sitzt im Referenz-Deployment-Klebstoff, nicht im besessenen Kern, muss aber authentifiziert und ratenbegrenzt sein, bevor Telefonie live geht.An open audit finding. It lives in the reference deployment glue, not in the owned core, but it must be authenticated and rate-limited before telephony goes live. M6
H3 — der Live-Claude-Pfad bricht nach einem WerkzeugaufrufH3 — the live Claude path breaks after a tool call Offener Prüfbefund, in CI unsichtbar, weil dort nur Mocks laufen. Es fehlt ein Loopback-Vertragstest, der den Rollenwechsel prüft. Bis dahin: keine Live-Werkzeugnutzung annehmen.An open audit finding, invisible in CI because only mocks run there. It needs a loopback contract test that validates role alternation. Until then, do not assume live tool use works. M6
Keine Ratenbegrenzung, nirgendsNo rate limiting, anywhere Auch nicht auf dem Konsolen-Login — die rund 25 ms von argon2id sind die einzige Bremse — und auch nicht bei der Webhook-Zustellung.Not on the console login either — argon2id's roughly 25 ms is the only brake — and not on webhook delivery. M7
Kein Widerruf von SitzungenNo session revocation Cookies sind zustandslos mit zwölf Stunden Laufzeit. Einen Benutzer zu löschen oder eine Rolle herabzustufen entwertet eine bereits ausgestellte Sitzung nicht; das Abmelden löscht nur das Cookie im Browser.Cookies are stateless with a twelve-hour life. Deleting a user or demoting a role does not invalidate an outstanding session; logging out only clears the client-side cookie. M7
Kein Endpunkt für Mandanten-Anlage und SchlüsselausgabeNo endpoint for tenant provisioning or key issuance Die Mandanten-Registry ist im Speicher und wird aus der Umgebung befüllt. Die Admin-Konsole zeigt den serverseitigen Aufruf an, statt so zu tun, als führte sie ihn aus. Die Schnittstelle steht fest, damit der Austausch später nichts anderes berührt.The tenant registry is in memory and seeded from the environment. The admin console shows the server-side call rather than pretending to perform it. The interface is fixed, so the later swap touches nothing else. M7
Kein Bildmodell für Avatare verdrahtetNo image model wired for avatars Avatar-Vorschläge erscheinen als Prompt-Briefings, und die Oberfläche sagt genau das. Es wird kein Erfolg vorgetäuscht.Avatar proposals render as prompt briefs, and the interface says exactly that. No success is faked. —
Echte Motoren und SIP-TelefonieReal engines and SIP telephony Die Adapter sind geschrieben, aber grün ist heute alles auf Mocks. Der Live-Nachweis — ein echter Anruf, der durchläuft — steht noch aus und hängt an Zugangsdaten, einem SIP-Trunk und einer Rufnummer.The adapters are written, but everything green today is green on mocks. The live proof — a real call that completes — is still outstanding and depends on credentials, a SIP trunk and a phone number. M6
Das Ingest-Token gilt der Plattform, nicht dem MandantenThe ingest token is a platform credential, not a tenant one Voice-Worker sind Plattform-Infrastruktur, deshalb reist der Mandant im (geprüften) Rumpf mit. Mandantenspezifische Ingest-Zugangsdaten kommen später.Voice workers are platform infrastructure, so the tenant travels in the (validated) body. Per-tenant ingest credentials come later. M7
Wissens-Intake: Datei, URL und Ernte sind noch lokalKnowledge intake: file, URL and harvest are still local Getippter Text legt einen echten Entwurf an. Die übrigen Wege stellen sich lokal in eine Warteschlange und sind sichtbar als „wartet auf Backend“ gekennzeichnet.Typed text files a real draft. The other paths queue locally and are visibly labelled as awaiting a backend. —
/openapi.json und /docs sind öffentlich/openapi.json and /docs are public Sie legen die Routenoberfläche offen. Als informativ eingestuft, nicht als Blocker — aber wer das nicht will, blendet sie im Reverse-Proxy aus.They disclose the route surface. Classified as informational, not a blocker — but an operator who does not want that hides them at the reverse proxy. —