Retour à Pulse
    Développeurs · Patrons

    Patrons d'intégration

    Scénarios concrets de bout en bout que les développeurs construisent réellement, quels endpoints utiliser, dans quel ordre, avec assez de code pour copier-coller.

    Retour au hub développeurs

    Patron 1, Pont d'événements de votre SaaS vers Pulse

    Votre SaaS émet des webhooks (facturation, e-commerce, planification, interne). Pulse génère une URL publique + un secret HMAC par source ; chaque charge utile vérifiée publie vers un topic qui réveille votre pipeline.

    python
    1import requests, hmac, hashlib, json, time
    2
    3PULSE_URL = "https://pulse.yourdomain.com"
    4SECRET = "your-webhook-secret"
    5
    6def publish_to_pulse(source_id, key, payload_dict):
    7    body = json.dumps(payload_dict).encode()
    8    signature = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
    9    timestamp = str(int(time.time()))
    10    r = requests.post(
    11        f"{PULSE_URL}/api/webhooks/{source_id}",
    12        headers={
    13            "Content-Type": "application/json",
    14            "X-Pulse-Signature": signature,
    15            "X-Pulse-Timestamp": timestamp,
    16            "X-Pulse-Event-Key": key,
    17        },
    18        data=body,
    19        timeout=10,
    20    )
    21    r.raise_for_status()
    22
    23publish_to_pulse("billing-ingress", "evt-abc", {"amount": 9900, "customer": "cus_123"})

    Pulse vérifie le HMAC avant de publier l'événement, rejetant les contrefaçons.

    Patron 2, GitOps pour les déploiements d'agents

    Les définitions de pipeline vivent dans Git. Les fusions de PR s'appliquent à la pré-production ; un flux de promotion s'applique à la production. Même script d'application par environnement.

    yaml
    1# .github/workflows/pulse-sync.yaml
    2on:
    3  push:
    4    branches: [main]
    5    paths: ['infra/pulse-staging/**']
    6
    7jobs:
    8  sync-staging:
    9    runs-on: ubuntu-latest
    10    steps:
    11      - uses: actions/checkout@v4
    12      - name: Apply
    13        env:
    14          PULSE_URL:  ${{ vars.PULSE_STAGING_URL }}
    15          PULSE_USER: ${{ secrets.PULSE_STAGING_USER }}
    16          PULSE_PASS: ${{ secrets.PULSE_STAGING_PASS }}
    17        run: |
    18          LOGIN=$(curl -sf -X POST "$PULSE_URL/api/auth/login" \
    19            -H "Content-Type: application/json" \
    20            -d "{\"username\":\"$PULSE_USER\",\"password\":\"$PULSE_PASS\"}")
    21          export PULSE_TOKEN=$(echo $LOGIN | jq -r '.accessToken')
    22          export CSRF=$(echo $LOGIN | jq -r '.csrfToken')
    23          cd infra/pulse-staging
    24          ../../scripts/apply-agents.sh
    25          ../../scripts/apply-pipelines.sh

    Patron 3, ETL temps réel vers votre entrepôt de données

    Reflétez chaque décision Pulse dans votre entrepôt pour la BI. Abonnez-vous via WebSocket ; insérez à mesure que les événements arrivent. Utilisez le polling REST sur /api/pulse/events?since=<cursor> comme complément de rattrapage pour la sémantique au-moins-une-fois.

    python
    1# etl.py, long-running service, subscribes and inserts
    2import asyncio, websockets, json, psycopg2, os
    3
    4PULSE_WS = os.environ["PULSE_WS_URL"]       # ws://pulse:9091/ws
    5TOKEN    = os.environ["PULSE_TOKEN"]
    6DB_URL   = os.environ["DATABASE_URL"]
    7
    8async def run():
    9    conn = psycopg2.connect(DB_URL)
    10    cur = conn.cursor()
    11    async with websockets.connect(PULSE_WS) as ws:
    12        await ws.send(json.dumps({"type": "auth", "token": TOKEN}))
    13        async for raw in ws:
    14            msg = json.loads(raw)
    15            if msg["type"] == "events":
    16                data = msg["data"]
    17                cur.execute(
    18                    "INSERT INTO pulse_events (id, topic, ts, payload) VALUES (%s, %s, %s, %s::jsonb)",
    19                    (data["id"], data["topic"], data["timestamp"], json.dumps(data["payload"])),
    20                )
    21                conn.commit()
    22
    23asyncio.run(run())

    Patron 4, Utiliser un agent Pulse comme outil externe

    Vous avez construit un pipeline Pulse utile. Vous voulez qu'un assistant bureau ou un autre hôte d'agent l'appelle.

    Chemin le plus rapide, endpoint natif (sans pont)

    Pulse expose un endpoint d'appel d'outils conforme à POST /tools. Pointez votre hôte directement dessus et chaque outil Pulse apparaît.

    json
    1{
    2  "toolServers": {
    3    "pulse": {
    4      "type": "http",
    5      "url": "http://localhost:9090/tools",
    6      "headers": {
    7        "Authorization": "Bearer <your-pulse-access-token>"
    8      }
    9    }
    10  }
    11}

    Alternative, pont stdio (un outil nommé unique)

    Utile quand votre hôte ne parle que stdio, ou quand vous voulez exposer un pipeline spécifique comme un seul outil nommé avec une sémantique synthétisée.

    python
    1# ~/.pulse-bridge/bridge.py
    2import asyncio, os, requests, json, uuid, time
    3from tool_server import Server
    4import tool_server.stdio
    5
    6PULSE_URL = os.environ["PULSE_URL"]
    7PULSE_TOKEN = os.environ["PULSE_TOKEN"]
    8
    9srv = Server("pulse-bridge")
    10
    11@srv.tool()
    12async def summarize_inbox(since_iso: str) -> str:
    13    """Use the Pulse email-summariser agent to summarise recent emails."""
    14    key = f"host-{uuid.uuid4()}"
    15    publish = requests.post(f"{PULSE_URL}/api/pulse/events",
    16        headers={"Authorization": f"Bearer {PULSE_TOKEN}"},
    17        json={"topic": "inbox.summarise.request",
    18              "key": key,
    19              "value": json.dumps({"since": since_iso})}).json()
    20    started = publish["timestamp"]
    21    for _ in range(45):
    22        time.sleep(1)
    23        r = requests.get(f"{PULSE_URL}/api/pulse/events",
    24            headers={"Authorization": f"Bearer {PULSE_TOKEN}"},
    25            params={"topic": "inbox.summarise.result", "since": started}).json()
    26        for e in r.get("events", []):
    27            if e.get("key") == key:
    28                return e["value"]
    29    raise RuntimeError("Timeout")
    30
    31if __name__ == "__main__":
    32    asyncio.run(tool_server.stdio.stdio_server(srv))

    Patron 5, Création d'agents programmatique depuis votre assistant

    Vous construisez un produit au-dessus de Pulse. Les utilisateurs configurent leur workflow dans VOTRE UI ; vous provisionnez les agents Pulse correspondants en coulisses, créer, planifier, démarrer, mettre à jour, supprimer.

    typescript
    1// backend.ts, your product's API
    2import { PulseClient } from './pulse-client';
    3
    4export async function provisionUserWorkflow(userConfig: UserWorkflow) {
    5  const pulse = new PulseClient(process.env.PULSE_URL!);
    6  await pulse.login(process.env.PULSE_BOT_USER!, process.env.PULSE_BOT_PASS!);
    7
    8  const agent = await pulse.call('POST', '/api/pulse/agents', {
    9    name: `user-${userConfig.userId}-workflow`,
    10    engine: 'llm',
    11    inputTopic: `user-${userConfig.userId}.inbound`,
    12    outputTopic: `user-${userConfig.userId}.outbound`,
    13    config: {
    14      systemPrompt: buildPrompt(userConfig),
    15      externalTools: userConfig.enabledTools,
    16    },
    17  });
    18
    19  await pulse.call('POST', '/api/pulse/schedules', {
    20    pipelineOrAgentId: agent.id,
    21    cron: userConfig.cron,
    22    timezone: userConfig.timezone,
    23  });
    24
    25  await pulse.call('POST', `/api/pulse/agents/${agent.id}/start`);
    26  return { agentId: agent.id };
    27}

    Patron 6, Supervision Pulse depuis Grafana

    Pulse expose des métriques Prometheus sur /metrics. Récupérez-les, construisez des tableaux de bord, alertez sur la dérive et les sauvegardes anciennes.

    yaml
    1# prometheus.yaml
    2scrape_configs:
    3  - job_name: 'pulse'
    4    scrape_interval: 30s
    5    static_configs:
    6      - targets: ['pulse.internal:9090']
    7    metrics_path: /metrics
    pulse_agents_running

    Agents actifs au fil du temps.

    pulse_agents_drifted

    Le watchdog n'a pas pu auto-récupérer.

    pulse_events_total

    Compteur cumulé d'événements par topic.

    pulse_backup_age_seconds

    Heures depuis la dernière sauvegarde ; alerte > 48 h.

    Règles Alertmanager

    yaml
    1groups:
    2  - name: pulse
    3    rules:
    4      - alert: PulseAgentsDrifted
    5        expr: pulse_agents_drifted > 0
    6        for: 10m
    7        annotations:
    8          summary: "Pulse has {{ $value }} drifted agents, watchdog didn't auto-recover"
    9      - alert: PulseBackupStale
    10        expr: pulse_backup_age_seconds > 48 * 3600
    11        for: 1h

    Patron 7, Import en masse d'événements historiques

    Migration depuis un autre système ? Rejouez l'historique dans Pulse. Posez un en-tête backfill: true pour que les agents puissent filtrer, évite les effets de bord réels (emails, notifications) pendant l'import.

    python
    1import requests, json
    2
    3PULSE = "http://localhost:9090"
    4TOKEN = "..."
    5
    6with open('historical-events.jsonl') as f:
    7    for line in f:
    8        ev = json.loads(line)
    9        requests.post(f"{PULSE}/api/pulse/events",
    10            headers={"Authorization": f"Bearer {TOKEN}"},
    11            json={
    12                "topic": ev["topic"],
    13                "key": ev["key"],
    14                "value": json.dumps(ev["payload"]),
    15                "headers": {
    16                    "backfill": "true",
    17                    "originalTimestamp": ev["timestamp"],
    18                },
    19            })

    Limite : ~300 événements/s sur une installation mono-nœud. Pour les imports plus volumineux, publiez par lots avec backoff.

    Patron 8, Variantes de pipeline avec feature flags

    Testez un nouveau prompt sur 10 % du trafic. Routez de façon déterministe avec un agent rule-based, puis comparez les sorties entre live et candidat.

    yaml
    1# agents/email-triager-router.yaml, routes 10% to candidate, 90% to live
    2name: email-triager-router
    3engine: rule-based
    4inputTopic: email.ingress
    5outputTopic: email.ingress.10pct
    6config:
    7  rules:
    8    - condition: "hash(messageId) % 10 == 0"
    9      action: emit
    10      target: email.ingress.10pct
    11    - condition: always
    12      action: emit
    13      target: email.ingress.90pct

    Ou utilisez la fonctionnalité native de shadow-deploy de Pulse, qui fait cela sans routage rule-based.

    Patron 9, Pulse multi-tenant (scénario MSP)

    Option 1, Une installation par client

    Le plus simple. Chaque client a son propre répertoire de données, domaine et licence. Lancez N processus derrière un reverse proxy ; routez par sous-domaine. Fonctionne d'emblée.

    Option 2, Une installation, multi-org

    Fonctionnalité Enterprise. Plusieurs organisations partagent un même binaire Pulse ; isolation des données et utilisateurs par org. Nécessite une licence Enterprise.

    Patron 10, Intégrer Pulse dans votre produit

    Rebrand de l'UI, exposez votre propre API aux utilisateurs finaux, conservez les identifiants admin Pulse dans votre backend. Les utilisateurs finaux s'authentifient contre VOTRE auth, pas celle de Pulse.

    La redistribution commerciale nécessite un accord Enterprise, contactez-nous avant la mise en production.

    Besoin d'aide pour un patron personnalisé ?

    Notre équipe peut revoir votre architecture et recommander la forme d'intégration la plus propre.

    Nous contacter