Files
simplex-chat/apps/simplex-support-bot/src/grok.ts
T
Narasimha-sc 5a3dfdd2b4 SimpleX support bot (#6625)
* plans: 20260207-support-bot.md

* Update 20260207-support-bot.md

* plans: 20260207-support-bot-implementation.md

* plans: Update 20260207-support-bot-implementation.md

* Relocate plans

* apps: support bot code & tests

* apps: support bot relocate

* support-bot: Fix basic functionality

* apps: support-bot /add command & fixes

* apps: simplex-support-bot: Change Grok logo

* Further usability improvements

* simplex-support-bot: Update support plan to reflect current flow

* simplex-support-bot: update product design plan

* support-bot: update plan

* support-bot: review and refine product spec

* support-bot: update product spec — complete state, /join team-only, card debouncing

- Group preferences applied once at creation, not on every startup
- /join restricted to team group only
- Team/Grok reply or reaction auto-completes conversation ()
- Customer message reverts to incomplete
- Card updates debounced globally with 15-minute batch flush

* support-bot: update implementation plan

* support-bot: implement stateless bot with cards, Grok, team flow, hardening

Complete rewrite of the support bot to stateless architecture:
- State derived from group composition + chat history (survives restarts)
- Card dashboard in team group with live status, preview, /join commands
- Two-profile architecture (main + Grok) with profileMutex serialization
- Grok join race condition fix via bufferedGrokInvitations
- Card preview: newest-first truncation, newline sanitization, sender prefixes
- Best-effort startup (invite link, group profile update)
- Team group preferences: directMessages, fullDelete, commands
- 122 tests across 27 suites

* support-bot: use apiCreateMemberContact and apiSendMemberContactInvitation instead of raw commands

Replace sendChatCmd("/_create member contact ...") and sendChatCmd("/_invite member contact ...")
with the typed API methods added in simplex-chat-nodejs. Update plans and build script accordingly.

* plans: 20260207-support-bot.md

* Update 20260207-support-bot.md

* plans: 20260207-support-bot-implementation.md

* plans: Update 20260207-support-bot-implementation.md

* Relocate plans

* apps: support bot code & tests

* apps: support bot relocate

* support-bot: Fix basic functionality

* apps: support-bot /add command & fixes

* apps: simplex-support-bot: Change Grok logo

* Further usability improvements

* simplex-support-bot: Update support plan to reflect current flow

* simplex-support-bot: update product design plan

* support-bot: update plan

* support-bot: review and refine product spec

* support-bot: update product spec — complete state, /join team-only, card debouncing

- Group preferences applied once at creation, not on every startup
- /join restricted to team group only
- Team/Grok reply or reaction auto-completes conversation ()
- Customer message reverts to incomplete
- Card updates debounced globally with 15-minute batch flush

* support-bot: update implementation plan

* support-bot: implement stateless bot with cards, Grok, team flow, hardening

Complete rewrite of the support bot to stateless architecture:
- State derived from group composition + chat history (survives restarts)
- Card dashboard in team group with live status, preview, /join commands
- Two-profile architecture (main + Grok) with profileMutex serialization
- Grok join race condition fix via bufferedGrokInvitations
- Card preview: newest-first truncation, newline sanitization, sender prefixes
- Best-effort startup (invite link, group profile update)
- Team group preferences: directMessages, fullDelete, commands
- 122 tests across 27 suites

* support-bot: use apiCreateMemberContact and apiSendMemberContactInvitation instead of raw commands

Replace sendChatCmd("/_create member contact ...") and sendChatCmd("/_invite member contact ...")
with the typed API methods added in simplex-chat-nodejs. Update plans and build script accordingly.

* support-bot: more improvemets

* support-bot: add tests for Grok batch dedup and initial response gating

7 new tests covering the duplicate Grok reply fix:
- batch dedup: only last customer message per group triggers API call
- batch dedup: multi-group batches handled independently
- batch dedup: non-customer messages filtered from batch
- initial response gating: per-message responses suppressed during activateGrok
- gating clears: per-message responses resume after activation completes

Update implementation plan test catalog (122 → 129 tests).

* support-bot: load context from context file

* Rename Grok AI -> Grok

* Remove unused strings.ts

* support-bot: change messages

* cardFlushMinutes 15 -> cardFlushSeconds 300

* support-bot: /team message when grok present

* support-bot: correct messages

* support-bot: update plans to reflect latest changes

* Update plan for state derivation

* support-bot: Update state machine plans

* support-bot: implement customData state

* Fix Grok revertStateOnFail race condition

* support-bot: plans adversarial review

* support-bot: /join ID part of card in plan

* support-bot: implement /join ID inside card

* support-bot: plans use params instead of regex in /join

* support-bot: Implement adversarial review changes

* support-bot: no re-invite if already invited

* support-bot: /team should give owner to invited member

* Don't change username for existing database

* support-bot: update bot commands before sending commands

* support-bot: adversarial review fixes

* support-bot: implement postgresql (#6876)

* support-bot: sqlite/postgres backend via typed DbConfig and parseArgs flags

* support-bot: add README with setup and flags reference

* support-bot: use published simplex-chat, drop build.sh/start.sh

* support-bot: switch CLI to commander, add --help

* support-bot: update README

---------

Co-authored-by: shum <github.shum@liber.li>
Co-authored-by: sh <37271604+shumvgolove@users.noreply.github.com>
2026-04-27 09:12:42 +01:00

56 lines
1.6 KiB
TypeScript

import {log, logError} from "./util.js"
export interface GrokMessage {
role: "system" | "user" | "assistant"
content: string
}
export class GrokApiClient {
private readonly apiKey: string
private readonly systemPrompt: string
constructor(apiKey: string, systemPrompt: string) {
this.apiKey = apiKey
this.systemPrompt = systemPrompt
}
async chatRaw(messages: GrokMessage[]): Promise<string> {
const response = await fetch("https://api.x.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.apiKey}`,
},
body: JSON.stringify({
model: "grok-3-mini",
messages,
temperature: 0.3,
max_tokens: 1024,
}),
signal: AbortSignal.timeout(60_000),
})
if (!response.ok) {
const body = await response.text()
logError(`Grok API HTTP ${response.status}`, body)
throw new Error(`Grok API error: HTTP ${response.status}`)
}
const data = await response.json() as {choices: {message: {content: string}}[]}
const content = data.choices?.[0]?.message?.content
if (!content) throw new Error("Grok API returned empty response")
log(`Grok API response: ${content.length} chars`)
return content
}
async chat(history: GrokMessage[], userMessage: string): Promise<string> {
log(`Grok API call: ${history.length} history msgs, user msg ${userMessage.length} chars`)
return this.chatRaw([
{role: "system", content: this.systemPrompt},
...history,
{role: "user", content: userMessage},
])
}
}