@sentrial/sdk 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { spawn } from 'node:child_process';\nimport os from 'node:os';\nimport path from 'node:path';\nimport process from 'node:process';\nimport readline from 'node:readline/promises';\n\nconst DEFAULT_API_URL = 'https://api.sentrial.com';\nconst CLI_VERSION = '0.4.5';\nconst CONFIG_DIR = path.join(os.homedir(), '.sentrial');\nconst CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\nconst TIME_RANGES = new Set(['24h', '3d', '7d', '30d']);\n\ntype FlagValue = string | boolean | undefined;\n\ninterface ParsedArgs {\n flags: Record<string, FlagValue>;\n positionals: string[];\n}\n\ninterface StoredConfig {\n apiKey?: string;\n apiUrl?: string;\n}\n\ninterface CliContext {\n apiKey?: string;\n apiUrl: string;\n json: boolean;\n color: boolean;\n}\n\ninterface ApiEnvelope<T> {\n data: T;\n meta?: Record<string, unknown>;\n}\n\ninterface SessionSummary {\n id: string;\n name?: string | null;\n agentName?: string | null;\n agentSlug?: string | null;\n userId?: string | null;\n status?: string | null;\n success?: boolean | null;\n failureReason?: string | null;\n totalEvents?: number | null;\n durationMs?: number | null;\n estimatedCost?: number | null;\n promptTokens?: number | null;\n completionTokens?: number | null;\n totalTokens?: number | null;\n score?: number | null;\n metricScores?: unknown;\n metricReasonings?: unknown;\n customMetrics?: unknown;\n userInput?: string | null;\n assistantOutput?: string | null;\n metadata?: unknown;\n detectedIssues?: unknown;\n createdAt?: string | null;\n completedAt?: string | null;\n}\n\ninterface EventSummary {\n id: string;\n sessionId: string;\n eventType: string;\n sequenceNumber?: number | null;\n timestamp?: string | null;\n toolName?: string | null;\n toolInput?: unknown;\n toolOutput?: unknown;\n toolError?: unknown;\n reasoning?: string | null;\n alternativesConsidered?: unknown;\n confidence?: number | null;\n estimatedCost?: number | null;\n tokenCount?: number | null;\n metadata?: unknown;\n traceId?: string | null;\n spanId?: string | null;\n}\n\ninterface SignalSummary {\n id: string;\n name: string;\n type: string;\n source?: string | null;\n count: number;\n affectedSessions: number;\n affectedUsers: number;\n description?: string | null;\n createdAt?: string | null;\n}\n\ninterface DiagnoseFinding {\n severity: 'high' | 'medium' | 'low' | 'info';\n title: string;\n detail: string;\n}\n\ninterface InstallPlan {\n language: 'typescript' | 'python';\n framework?: string;\n command: string;\n args: string[];\n packageName: string;\n}\n\nexport class CliError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = 'CliError';\n this.exitCode = exitCode;\n }\n}\n\nconst SHORT_FLAGS: Record<string, string> = {\n a: 'agent',\n f: 'force',\n h: 'help',\n j: 'json',\n l: 'last',\n s: 'status',\n t: 'type',\n v: 'version',\n y: 'yes',\n};\n\nconst BOOLEAN_FLAGS = new Set([\n 'force',\n 'help',\n 'include-api-key',\n 'json',\n 'dry-run',\n 'no-color',\n 'no-events',\n 'no-fail-on-regression',\n 'version',\n 'yes',\n]);\n\nconst HELP = `Sentrial CLI\n\nUsage:\n sentrial <command> [options]\n\nCommands:\n install Install the SDK package and scaffold integration files\n init Scaffold a safe example integration in this repo\n login Save an API key for future CLI calls\n sessions list List recent sessions\n sessions get <id> Show a session and its events\n events list <session-id> List events for a session\n signals list List detected signals\n diagnose <session-id> Print a terminal diagnosis from session events\n evaluate <experiment-id> Run the /api/v1/evaluate CI gate\n clusters Reserved for the upcoming clusters API\n fix <session-id> Reserved for the upcoming Fixer API\n replay <session-id> Reserved for the upcoming replay API\n\nGlobal options:\n --api-key <key> API key, otherwise SENTRIAL_API_KEY or ~/.sentrial/config.json\n --api-url <url> API URL, otherwise SENTRIAL_API_URL or ${DEFAULT_API_URL}\n --json Emit machine-readable JSON\n --no-color Disable ANSI color\n -h, --help Show help\n -v, --version Show version\n\nExamples:\n sentrial login --api-key sentrial_live_xxx\n sentrial install\n sentrial init\n sentrial sessions list --last 7d --status failed --agent support\n sentrial sessions get 00000000-0000-0000-0000-000000000000\n sentrial events list 00000000-0000-0000-0000-000000000000 --type tool_call\n sentrial signals list --type negative --last 30d\n sentrial diagnose 00000000-0000-0000-0000-000000000000\n sentrial evaluate 00000000-0000-0000-0000-000000000000 --min-score 80\n`;\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const flags: Record<string, FlagValue> = {};\n const positionals: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i];\n if (token === '--') {\n positionals.push(...argv.slice(i + 1));\n break;\n }\n\n if (token.startsWith('--no-')) {\n flags[token.slice(5)] = false;\n continue;\n }\n\n if (token.startsWith('--')) {\n const [rawName, inlineValue] = token.slice(2).split('=', 2);\n if (inlineValue !== undefined) {\n flags[rawName] = inlineValue;\n } else if (BOOLEAN_FLAGS.has(rawName)) {\n flags[rawName] = true;\n } else {\n const next = argv[i + 1];\n if (next && !next.startsWith('-')) {\n flags[rawName] = next;\n i++;\n } else {\n flags[rawName] = true;\n }\n }\n continue;\n }\n\n if (token.startsWith('-') && token.length === 2) {\n const mapped = SHORT_FLAGS[token.slice(1)];\n if (!mapped) {\n throw new CliError(`Unknown flag: ${token}`);\n }\n if (BOOLEAN_FLAGS.has(mapped)) {\n flags[mapped] = true;\n } else {\n const next = argv[i + 1];\n if (!next || next.startsWith('-')) {\n throw new CliError(`Flag ${token} requires a value`);\n }\n flags[mapped] = next;\n i++;\n }\n continue;\n }\n\n positionals.push(token);\n }\n\n return { flags, positionals };\n}\n\nfunction getFlag(flags: Record<string, FlagValue>, ...names: string[]): FlagValue {\n for (const name of names) {\n if (flags[name] !== undefined) return flags[name];\n }\n return undefined;\n}\n\nfunction getStringFlag(flags: Record<string, FlagValue>, ...names: string[]): string | undefined {\n const value = getFlag(flags, ...names);\n if (typeof value === 'string') return value;\n return undefined;\n}\n\nfunction getBooleanFlag(flags: Record<string, FlagValue>, name: string): boolean {\n return flags[name] === true;\n}\n\nfunction readConfig(): StoredConfig {\n if (!existsSync(CONFIG_FILE)) return {};\n\n try {\n const parsed = JSON.parse(readFileSync(CONFIG_FILE, 'utf8')) as StoredConfig;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction writeConfig(config: StoredConfig): void {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n writeFileSync(CONFIG_FILE, `${JSON.stringify(config, null, 2)}\\n`, { mode: 0o600 });\n try {\n chmodSync(CONFIG_FILE, 0o600);\n } catch {\n // Best effort only; some filesystems do not support chmod.\n }\n}\n\nfunction createContext(flags: Record<string, FlagValue>): CliContext {\n const config = readConfig();\n const apiKey = getStringFlag(flags, 'api-key') ?? process.env.SENTRIAL_API_KEY ?? config.apiKey;\n const apiUrl = (\n getStringFlag(flags, 'api-url') ??\n process.env.SENTRIAL_API_URL ??\n config.apiUrl ??\n DEFAULT_API_URL\n ).replace(/\\/$/, '');\n\n return {\n apiKey,\n apiUrl,\n json: getBooleanFlag(flags, 'json'),\n color: flags.color !== false && process.stdout.isTTY && !process.env.NO_COLOR,\n };\n}\n\nfunction requireApiKey(ctx: CliContext): string {\n if (!ctx.apiKey) {\n throw new CliError(\n 'Missing API key. Run `sentrial login --api-key sentrial_live_xxx` or set SENTRIAL_API_KEY.'\n );\n }\n return ctx.apiKey;\n}\n\nasync function apiRequest<T>(\n ctx: CliContext,\n apiPath: string,\n options: {\n method?: 'GET' | 'POST';\n query?: Record<string, string | number | boolean | undefined>;\n body?: unknown;\n } = {}\n): Promise<T> {\n const apiKey = requireApiKey(ctx);\n const url = new URL(apiPath, `${ctx.apiUrl}/`);\n\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n Accept: 'application/json',\n };\n\n if (options.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: options.method ?? 'GET',\n headers,\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n });\n } catch (error) {\n throw new CliError(\n `Could not reach ${ctx.apiUrl}. ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n const text = await response.text();\n const parsed = parseResponseBody(text);\n\n if (!response.ok) {\n throw new CliError(\n `${options.method ?? 'GET'} ${url.pathname} failed (${response.status}): ${formatApiError(\n parsed\n )}`,\n response.status === 404 ? 4 : 1\n );\n }\n\n return parsed as T;\n}\n\nfunction parseResponseBody(text: string): unknown {\n if (!text.trim()) return {};\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction formatApiError(value: unknown): string {\n if (value && typeof value === 'object') {\n const record = value as Record<string, unknown>;\n if (typeof record.error === 'string') return record.error;\n if (record.error && typeof record.error === 'object') {\n const error = record.error as Record<string, unknown>;\n if (typeof error.message === 'string') return error.message;\n }\n }\n return typeof value === 'string' ? value : 'Unexpected API response';\n}\n\nasync function commandLogin(ctx: CliContext, flags: Record<string, FlagValue>): Promise<void> {\n let apiKey = getStringFlag(flags, 'api-key') ?? process.env.SENTRIAL_API_KEY;\n const apiUrl = getStringFlag(flags, 'api-url') ?? process.env.SENTRIAL_API_URL ?? ctx.apiUrl;\n\n if (!apiKey) {\n if (!process.stdin.isTTY) {\n throw new CliError('Pass --api-key or set SENTRIAL_API_KEY when stdin is not interactive.');\n }\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n apiKey = (await rl.question('Sentrial API key: ')).trim();\n rl.close();\n }\n\n if (!apiKey.startsWith('sentrial_')) {\n throw new CliError('API keys should look like sentrial_live_xxx or sentrial_test_xxx.');\n }\n\n writeConfig({ apiKey, apiUrl });\n\n if (ctx.json) {\n printJson({ ok: true, configPath: CONFIG_FILE, apiUrl });\n return;\n }\n\n process.stdout.write(`Saved credentials to ${CONFIG_FILE}\\n`);\n}\n\nasync function commandInstall(ctx: CliContext, flags: Record<string, FlagValue>): Promise<void> {\n const projectRoot = process.cwd();\n const requestedLanguage = getStringFlag(flags, 'language');\n const pythonCommand = getStringFlag(flags, 'python');\n const packageOverride = getStringFlag(flags, 'sdk-package') ?? process.env.SENTRIAL_SDK_PACKAGE;\n const plan = buildInstallPlan(projectRoot, requestedLanguage, pythonCommand, packageOverride);\n const dryRun = getBooleanFlag(flags, 'dry-run');\n\n if (ctx.json) {\n if (!dryRun) {\n throw new CliError('Use --dry-run with --json; real installs stream package-manager output.');\n }\n printJson({ dryRun: true, plan, wouldWrite: plannedScaffoldFiles(projectRoot, plan.language) });\n return;\n }\n\n process.stdout.write(`Detected: ${plan.framework ?? plan.language}\\n`);\n process.stdout.write(`Install: ${formatCommand(plan.command, plan.args)}\\n`);\n\n if (dryRun) {\n process.stdout.write('Dry run only. No files were changed.\\n');\n return;\n }\n\n await runSubprocess(plan.command, plan.args, projectRoot);\n await commandInit(ctx, flags);\n}\n\nasync function commandInit(ctx: CliContext, flags: Record<string, FlagValue>): Promise<void> {\n const projectRoot = process.cwd();\n const detected = detectProject(projectRoot);\n const requestedLanguage = getStringFlag(flags, 'language');\n const language = requestedLanguage ?? detected.language ?? 'typescript';\n const force = getBooleanFlag(flags, 'force');\n const apiKey = getBooleanFlag(flags, 'include-api-key')\n ? (ctx.apiKey ?? 'sentrial_live_xxx')\n : 'sentrial_live_xxx';\n\n if (language !== 'typescript' && language !== 'python') {\n throw new CliError('Supported init languages are \"typescript\" and \"python\".');\n }\n\n const files =\n language === 'python'\n ? [\n {\n path: path.join(projectRoot, 'sentrial.example.py'),\n content: pythonExample(),\n },\n ]\n : [\n {\n path: path.join(projectRoot, 'sentrial.example.ts'),\n content: typescriptExample(),\n },\n ];\n\n files.push({\n path: path.join(projectRoot, '.env.sentrial.example'),\n content: `SENTRIAL_API_KEY=${apiKey}\\nSENTRIAL_API_URL=${ctx.apiUrl}\\n`,\n });\n\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const file of files) {\n if (existsSync(file.path) && !force) {\n skipped.push(file.path);\n continue;\n }\n writeFileSync(file.path, file.content);\n written.push(file.path);\n }\n\n const installCommand =\n language === 'python'\n ? 'pip install sentrial'\n : `${detectPackageManager(projectRoot)} add @sentrial/sdk`;\n\n if (ctx.json) {\n printJson({\n detected,\n language,\n installCommand,\n written,\n skipped,\n });\n return;\n }\n\n process.stdout.write(`Detected: ${detected.framework ?? language}\\n`);\n process.stdout.write(`Install: ${installCommand}\\n`);\n if (written.length > 0) {\n process.stdout.write(\n `Written:\\n${written.map((file) => ` ${path.relative(projectRoot, file)}`).join('\\n')}\\n`\n );\n }\n if (skipped.length > 0) {\n process.stdout.write(\n `Skipped existing files:\\n${skipped.map((file) => ` ${path.relative(projectRoot, file)}`).join('\\n')}\\n`\n );\n }\n}\n\nasync function commandSessions(\n ctx: CliContext,\n flags: Record<string, FlagValue>,\n rest: string[]\n): Promise<void> {\n const subcommand = rest[0];\n if (subcommand === 'list') {\n await commandSessionsList(ctx, flags);\n return;\n }\n if (subcommand === 'get') {\n const sessionId = rest[1];\n if (!sessionId) throw new CliError('Usage: sentrial sessions get <id>');\n await commandSessionsGet(ctx, flags, sessionId);\n return;\n }\n throw new CliError('Usage: sentrial sessions <list|get>');\n}\n\nasync function commandSessionsList(\n ctx: CliContext,\n flags: Record<string, FlagValue>\n): Promise<void> {\n const query = buildTimeQuery(flags);\n const agentFilter = getStringFlag(flags, 'agent')?.toLowerCase();\n const hasExplicitLimit = getStringFlag(flags, 'limit') !== undefined;\n query.status = getStringFlag(flags, 'status') ?? 'all';\n query.limit = parseIntegerFlag(flags, 'limit', agentFilter && !hasExplicitLimit ? 500 : 50);\n query.offset = parseIntegerFlag(flags, 'offset', 0);\n\n const response = await apiRequest<ApiEnvelope<SessionSummary[]>>(ctx, '/api/v1/sessions', {\n query,\n });\n\n const sessions = agentFilter\n ? response.data.filter((session) =>\n `${session.agentName ?? ''} ${session.agentSlug ?? ''}`.toLowerCase().includes(agentFilter)\n )\n : response.data;\n\n if (ctx.json) {\n printJson({ data: sessions, meta: response.meta });\n return;\n }\n\n if (sessions.length === 0) {\n process.stdout.write('No sessions found.\\n');\n return;\n }\n\n printTable(sessions, [\n { header: 'ID', render: (s) => s.id, maxWidth: 36 },\n { header: 'Agent', render: (s) => s.agentName ?? s.agentSlug ?? '-', maxWidth: 18 },\n { header: 'Status', render: (s) => s.status ?? '-', maxWidth: 10 },\n { header: 'Result', render: (s) => formatResult(s.success), maxWidth: 8 },\n { header: 'Score', render: (s) => formatNullableNumber(s.score), maxWidth: 6 },\n { header: 'Dur', render: (s) => formatDuration(s.durationMs), maxWidth: 8 },\n { header: 'Cost', render: (s) => formatCost(s.estimatedCost), maxWidth: 10 },\n { header: 'Created', render: (s) => formatDate(s.createdAt), maxWidth: 16 },\n { header: 'Name', render: (s) => s.name ?? '-', maxWidth: 28 },\n ]);\n\n if (agentFilter) {\n process.stdout.write(`\\nFiltered locally by agent: ${agentFilter}\\n`);\n }\n}\n\nasync function commandSessionsGet(\n ctx: CliContext,\n flags: Record<string, FlagValue>,\n sessionId: string\n): Promise<void> {\n const sessionResponse = await apiRequest<ApiEnvelope<SessionSummary>>(\n ctx,\n `/api/v1/sessions/${sessionId}`\n );\n const includeEvents = flags.events !== false;\n const events = includeEvents ? await fetchSessionEvents(ctx, flags, sessionId) : [];\n\n if (ctx.json) {\n printJson({ data: sessionResponse.data, events });\n return;\n }\n\n printSession(sessionResponse.data, events, ctx);\n}\n\nasync function fetchSessionEvents(\n ctx: CliContext,\n flags: Record<string, FlagValue>,\n sessionId: string\n): Promise<EventSummary[]> {\n const eventType = getStringFlag(flags, 'event-type') ?? 'all';\n const response = await apiRequest<ApiEnvelope<EventSummary[]>>(\n ctx,\n `/api/v1/sessions/${sessionId}/events`,\n {\n query: {\n limit: parseIntegerFlag(flags, 'events-limit', 100),\n offset: parseIntegerFlag(flags, 'events-offset', 0),\n eventType,\n },\n }\n );\n return response.data;\n}\n\nasync function commandEvents(\n ctx: CliContext,\n flags: Record<string, FlagValue>,\n rest: string[]\n): Promise<void> {\n const subcommand = rest[0] ?? 'list';\n if (subcommand !== 'list') {\n throw new CliError('Usage: sentrial events list <session-id>');\n }\n\n const sessionId = rest[1] ?? getStringFlag(flags, 'session', 'session-id');\n if (!sessionId) {\n throw new CliError('Usage: sentrial events list <session-id>');\n }\n\n const eventType = getStringFlag(flags, 'type', 'event-type') ?? 'all';\n const response = await apiRequest<ApiEnvelope<EventSummary[]>>(\n ctx,\n `/api/v1/sessions/${sessionId}/events`,\n {\n query: {\n limit: parseIntegerFlag(flags, 'limit', 100),\n offset: parseIntegerFlag(flags, 'offset', 0),\n eventType,\n },\n }\n );\n\n if (ctx.json) {\n printJson(response);\n return;\n }\n\n if (response.data.length === 0) {\n process.stdout.write('No events found.\\n');\n return;\n }\n\n process.stdout.write(`${bold(ctx, 'Events')} ${sessionId}\\n`);\n for (const event of response.data) {\n printEvent(event, ctx);\n }\n}\n\nasync function commandSignals(\n ctx: CliContext,\n flags: Record<string, FlagValue>,\n rest: string[]\n): Promise<void> {\n const subcommand = rest[0] ?? 'list';\n if (subcommand !== 'list') {\n throw new CliError('Usage: sentrial signals list');\n }\n\n const query = buildTimeQuery(flags);\n query.type = getStringFlag(flags, 'type') ?? 'all';\n query.source = getStringFlag(flags, 'source') ?? 'all';\n\n const response = await apiRequest<ApiEnvelope<SignalSummary[]>>(ctx, '/api/v1/signals', {\n query,\n });\n\n if (ctx.json) {\n printJson(response);\n return;\n }\n\n if (response.data.length === 0) {\n process.stdout.write('No signals found.\\n');\n return;\n }\n\n printTable(response.data, [\n { header: 'Name', render: (s) => s.name, maxWidth: 28 },\n { header: 'Type', render: (s) => s.type, maxWidth: 10 },\n { header: 'Source', render: (s) => s.source ?? '-', maxWidth: 12 },\n { header: 'Count', render: (s) => String(s.count), maxWidth: 8 },\n { header: 'Sessions', render: (s) => String(s.affectedSessions), maxWidth: 10 },\n { header: 'Users', render: (s) => String(s.affectedUsers), maxWidth: 8 },\n { header: 'Created', render: (s) => formatDate(s.createdAt), maxWidth: 16 },\n { header: 'Description', render: (s) => s.description ?? '-', maxWidth: 36 },\n ]);\n}\n\nasync function commandDiagnose(\n ctx: CliContext,\n flags: Record<string, FlagValue>,\n sessionId: string | undefined\n): Promise<void> {\n if (!sessionId) throw new CliError('Usage: sentrial diagnose <session-id>');\n\n const sessionResponse = await apiRequest<ApiEnvelope<SessionSummary>>(\n ctx,\n `/api/v1/sessions/${sessionId}`\n );\n const events = await fetchSessionEvents(ctx, flags, sessionId);\n const findings = diagnoseSession(sessionResponse.data, events);\n\n if (ctx.json) {\n printJson({ session: sessionResponse.data, findings });\n return;\n }\n\n process.stdout.write(`${bold(ctx, 'Diagnosis')}\\n`);\n process.stdout.write(`Session: ${sessionResponse.data.id}\\n`);\n process.stdout.write(\n `Agent: ${sessionResponse.data.agentName ?? sessionResponse.data.agentSlug ?? '-'}\\n`\n );\n process.stdout.write(\n `Status: ${sessionResponse.data.status ?? '-'} (${formatResult(sessionResponse.data.success)})\\n`\n );\n if (sessionResponse.data.failureReason) {\n process.stdout.write(`Failure: ${sessionResponse.data.failureReason}\\n`);\n }\n process.stdout.write('\\n');\n\n if (findings.length === 0) {\n process.stdout.write('No obvious terminal-level issues found in the session events.\\n');\n return;\n }\n\n for (const finding of findings) {\n process.stdout.write(`${severityLabel(ctx, finding.severity)} ${finding.title}\\n`);\n process.stdout.write(` ${finding.detail}\\n`);\n }\n}\n\nasync function commandEvaluate(\n ctx: CliContext,\n flags: Record<string, FlagValue>,\n experimentId: string | undefined\n): Promise<void> {\n const resolvedExperimentId = experimentId ?? getStringFlag(flags, 'experiment', 'experiment-id');\n if (!resolvedExperimentId) {\n throw new CliError('Usage: sentrial evaluate <experiment-id> [--min-score 80]');\n }\n\n const body = {\n experimentId: resolvedExperimentId,\n baselineExperimentId: getStringFlag(flags, 'baseline', 'baseline-experiment-id'),\n thresholds: {\n minScore: parseOptionalNumberFlag(flags, 'min-score'),\n failOnRegression: flags['fail-on-regression'] === false ? false : undefined,\n maxRegressionPercent: parseOptionalNumberFlag(flags, 'max-regression-percent'),\n },\n };\n\n const response = await apiRequest<Record<string, unknown>>(ctx, '/api/v1/evaluate', {\n method: 'POST',\n body,\n });\n\n if (ctx.json) {\n printJson(response);\n } else {\n const passed = response.passed === true;\n process.stdout.write(`${passed ? color(ctx, 'green', 'PASS') : color(ctx, 'red', 'FAIL')}\\n`);\n if (Array.isArray(response.failures) && response.failures.length > 0) {\n process.stdout.write(\n `Failures:\\n${response.failures.map((f) => ` - ${String(f)}`).join('\\n')}\\n`\n );\n }\n if (response.summary && typeof response.summary === 'object') {\n printKeyValues(response.summary as Record<string, unknown>);\n }\n if (response.regression && typeof response.regression === 'object') {\n process.stdout.write('\\nRegression:\\n');\n printKeyValues(response.regression as Record<string, unknown>);\n }\n }\n\n if (response.passed === false) {\n process.exitCode = 1;\n }\n}\n\nfunction commandReserved(command: string): void {\n const messages: Record<string, string> = {\n clusters: 'The clusters CLI is reserved for the upcoming /api/v1/clusters endpoint.',\n fix: 'The Fixer CLI is reserved for the upcoming scriptable Fixer API.',\n replay: 'The replay CLI is reserved for the upcoming replay API.',\n };\n throw new CliError(messages[command] ?? `${command} is not available yet.`, 2);\n}\n\nfunction buildTimeQuery(flags: Record<string, FlagValue>): Record<string, string | number> {\n const query: Record<string, string | number> = {};\n const last = getStringFlag(flags, 'last', 'time-range') ?? '7d';\n const from = getStringFlag(flags, 'from');\n const to = getStringFlag(flags, 'to');\n\n if (from) {\n query.from = from;\n } else if (TIME_RANGES.has(last)) {\n query.timeRange = last;\n } else {\n throw new CliError(`--last must be one of: ${Array.from(TIME_RANGES).join(', ')}`);\n }\n\n if (to) query.to = to;\n return query;\n}\n\nfunction parseIntegerFlag(\n flags: Record<string, FlagValue>,\n name: string,\n fallback: number\n): number {\n const raw = getStringFlag(flags, name);\n if (raw === undefined) return fallback;\n const parsed = Number.parseInt(raw, 10);\n if (!Number.isFinite(parsed)) throw new CliError(`--${name} must be an integer`);\n return parsed;\n}\n\nfunction parseOptionalNumberFlag(\n flags: Record<string, FlagValue>,\n name: string\n): number | undefined {\n const raw = getStringFlag(flags, name);\n if (raw === undefined) return undefined;\n const parsed = Number.parseFloat(raw);\n if (!Number.isFinite(parsed)) throw new CliError(`--${name} must be a number`);\n return parsed;\n}\n\nexport function diagnoseSession(\n session: SessionSummary,\n events: EventSummary[]\n): DiagnoseFinding[] {\n const findings: DiagnoseFinding[] = [];\n const toolErrors = events.filter((event) => hasMeaningfulValue(event.toolError));\n const explicitErrors = events.filter((event) => event.eventType === 'error');\n const lowConfidence = events.filter(\n (event) => typeof event.confidence === 'number' && event.confidence < 0.5\n );\n\n if (session.success === false || session.status === 'failed') {\n findings.push({\n severity: 'high',\n title: 'Session ended unsuccessfully',\n detail: session.failureReason ?? 'The session is marked failed without a failure reason.',\n });\n }\n\n if (toolErrors.length > 0) {\n const grouped = groupBy(toolErrors, (event) => event.toolName ?? 'unknown_tool');\n const top = Array.from(grouped.entries())\n .map(([tool, group]) => `${tool} (${group.length})`)\n .join(', ');\n findings.push({\n severity: 'high',\n title: 'Tool errors occurred',\n detail: `${toolErrors.length} tool error event(s): ${top}. First error: ${formatCompactJson(\n toolErrors[0].toolError\n )}`,\n });\n }\n\n if (explicitErrors.length > 0) {\n findings.push({\n severity: 'high',\n title: 'Error events were recorded',\n detail: `${explicitErrors.length} error event(s). First event: ${summarizeEvent(\n explicitErrors[0]\n )}`,\n });\n }\n\n const repeatedCalls = findRepeatedToolCalls(events);\n if (repeatedCalls.length > 0) {\n findings.push({\n severity: 'medium',\n title: 'Repeated identical tool calls',\n detail: repeatedCalls\n .slice(0, 3)\n .map((call) => `${call.toolName} repeated ${call.count} times`)\n .join('; '),\n });\n }\n\n if (lowConfidence.length > 0) {\n findings.push({\n severity: 'medium',\n title: 'Low-confidence decisions',\n detail: `${lowConfidence.length} decision event(s) had confidence below 0.5.`,\n });\n }\n\n if (session.totalTokens && session.totalTokens > 100_000) {\n findings.push({\n severity: 'low',\n title: 'High token usage',\n detail: `This session used ${session.totalTokens.toLocaleString()} tokens.`,\n });\n }\n\n if (session.durationMs && session.durationMs > 120_000) {\n findings.push({\n severity: 'low',\n title: 'Long-running session',\n detail: `Duration was ${formatDuration(session.durationMs)}.`,\n });\n }\n\n if (session.status === 'completed' && !session.assistantOutput) {\n findings.push({\n severity: 'info',\n title: 'No assistant output stored',\n detail:\n 'The session completed, but assistantOutput is empty. Confirm finish({ output }) is wired.',\n });\n }\n\n return findings;\n}\n\nfunction findRepeatedToolCalls(events: EventSummary[]): Array<{ toolName: string; count: number }> {\n const counts = new Map<string, { toolName: string; count: number }>();\n for (const event of events) {\n if (event.eventType !== 'tool_call' || !event.toolName) continue;\n const key = `${event.toolName}:${formatCompactJson(event.toolInput)}`;\n const current = counts.get(key) ?? { toolName: event.toolName, count: 0 };\n current.count++;\n counts.set(key, current);\n }\n return Array.from(counts.values()).filter((entry) => entry.count >= 3);\n}\n\nfunction groupBy<T>(items: T[], keyFor: (item: T) => string): Map<string, T[]> {\n const result = new Map<string, T[]>();\n for (const item of items) {\n const key = keyFor(item);\n const existing = result.get(key) ?? [];\n existing.push(item);\n result.set(key, existing);\n }\n return result;\n}\n\nfunction hasMeaningfulValue(value: unknown): boolean {\n if (value === null || value === undefined) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\nexport function detectProject(projectRoot: string): {\n language?: 'typescript' | 'python';\n framework?: string;\n} {\n const packageJsonPath = path.join(projectRoot, 'package.json');\n if (existsSync(packageJsonPath)) {\n try {\n const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps.next) return { language: 'typescript', framework: 'Next.js' };\n if (deps.ai || deps['@ai-sdk/openai'])\n return { language: 'typescript', framework: 'Vercel AI SDK' };\n if (deps.langchain || deps['@langchain/core'])\n return { language: 'typescript', framework: 'LangChain' };\n if (deps.openai) return { language: 'typescript', framework: 'OpenAI Node' };\n return { language: 'typescript', framework: 'Node.js' };\n } catch {\n return { language: 'typescript', framework: 'Node.js' };\n }\n }\n\n const requirementsPath = path.join(projectRoot, 'requirements.txt');\n const pyprojectPath = path.join(projectRoot, 'pyproject.toml');\n if (existsSync(requirementsPath) || existsSync(pyprojectPath)) {\n const text = [requirementsPath, pyprojectPath]\n .filter((file) => existsSync(file))\n .map((file) => readFileSync(file, 'utf8').toLowerCase())\n .join('\\n');\n if (text.includes('fastapi')) return { language: 'python', framework: 'FastAPI' };\n if (text.includes('langchain')) return { language: 'python', framework: 'LangChain' };\n if (text.includes('crewai')) return { language: 'python', framework: 'CrewAI' };\n if (text.includes('openai')) return { language: 'python', framework: 'OpenAI Python' };\n return { language: 'python', framework: 'Python' };\n }\n\n return {};\n}\n\nexport function buildInstallPlan(\n projectRoot: string,\n languageOverride?: string,\n pythonCommand?: string,\n packageOverride?: string\n): InstallPlan {\n const detected = detectProject(projectRoot);\n const language = languageOverride ?? detected.language ?? 'typescript';\n\n if (language !== 'typescript' && language !== 'python') {\n throw new CliError('Supported install languages are \"typescript\" and \"python\".');\n }\n\n if (language === 'python') {\n const command = pythonCommand ?? (process.platform === 'win32' ? 'python' : 'python3');\n const packageName = packageOverride ?? 'sentrial';\n return {\n language,\n framework: detected.framework,\n command,\n args: ['-m', 'pip', 'install', packageName],\n packageName,\n };\n }\n\n const packageManager = detectPackageManager(projectRoot);\n const packageName = packageOverride ?? '@sentrial/sdk';\n return {\n language,\n framework: detected.framework,\n command: packageManager,\n args: packageManager === 'npm' ? ['install', packageName] : ['add', packageName],\n packageName,\n };\n}\n\nfunction detectPackageManager(projectRoot: string): 'pnpm' | 'npm' | 'yarn' {\n if (existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';\n return 'npm';\n}\n\nfunction plannedScaffoldFiles(projectRoot: string, language: InstallPlan['language']): string[] {\n const sampleFile = language === 'python' ? 'sentrial.example.py' : 'sentrial.example.ts';\n return [path.join(projectRoot, sampleFile), path.join(projectRoot, '.env.sentrial.example')];\n}\n\nfunction runSubprocess(command: string, args: string[], cwd: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n stdio: 'inherit',\n shell: process.platform === 'win32',\n });\n\n child.on('error', (error) => {\n reject(new CliError(`Failed to run ${formatCommand(command, args)}: ${error.message}`));\n });\n\n child.on('close', (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n reject(\n new CliError(`${formatCommand(command, args)} failed with exit code ${code ?? 'unknown'}`)\n );\n });\n });\n}\n\nfunction formatCommand(command: string, args: string[]): string {\n return [command, ...args].join(' ');\n}\n\nfunction typescriptExample(): string {\n return `import { configure, withSession } from '@sentrial/sdk';\n\nconfigure({\n apiKey: process.env.SENTRIAL_API_KEY,\n apiUrl: process.env.SENTRIAL_API_URL,\n});\n\nexport const runAgent = withSession('my-agent', async (userId: string, input: string) => {\n // Replace this with your real agent call. LLM/tool wrappers can be added around it.\n const output = \\`Echo: \\${input}\\`;\n return output;\n});\n\nawait runAgent('user_123', 'Hello from Sentrial');\n`;\n}\n\nfunction pythonExample(): string {\n return `from sentrial import SentrialClient\n\nclient = SentrialClient()\n\ninteraction = client.begin(\n user_id=\"user_123\",\n event=\"my-agent\",\n input=\"Hello from Sentrial\",\n)\n\ntry:\n # Replace this with your real agent call.\n output = \"Echo: Hello from Sentrial\"\n interaction.finish(output=output, success=True)\nexcept Exception as exc:\n interaction.finish(success=False, failure_reason=str(exc))\n raise\n`;\n}\n\nfunction printSession(session: SessionSummary, events: EventSummary[], ctx: CliContext): void {\n process.stdout.write(`${bold(ctx, 'Session')} ${session.id}\\n`);\n printKeyValues({\n name: session.name ?? '-',\n agent: session.agentName ?? session.agentSlug ?? '-',\n userId: session.userId ?? '-',\n status: `${session.status ?? '-'} (${formatResult(session.success)})`,\n score: formatNullableNumber(session.score),\n duration: formatDuration(session.durationMs),\n cost: formatCost(session.estimatedCost),\n tokens: session.totalTokens ?? '-',\n events: session.totalEvents ?? events.length,\n createdAt: formatDate(session.createdAt),\n completedAt: formatDate(session.completedAt),\n });\n\n if (session.failureReason) {\n process.stdout.write(`\\nFailure reason:\\n${indent(wrap(session.failureReason))}\\n`);\n }\n if (session.userInput) {\n process.stdout.write(`\\nInput:\\n${indent(wrap(session.userInput))}\\n`);\n }\n if (session.assistantOutput) {\n process.stdout.write(`\\nOutput:\\n${indent(wrap(session.assistantOutput))}\\n`);\n }\n\n if (events.length > 0) {\n process.stdout.write(`\\n${bold(ctx, 'Events')}\\n`);\n for (const event of events) {\n printEvent(event, ctx);\n }\n }\n}\n\nfunction printEvent(event: EventSummary, ctx: CliContext): void {\n const prefix = `#${event.sequenceNumber ?? '-'} ${event.eventType}`;\n const label =\n event.eventType === 'error' || hasMeaningfulValue(event.toolError)\n ? color(ctx, 'red', prefix)\n : color(ctx, 'cyan', prefix);\n process.stdout.write(`${label} ${formatDate(event.timestamp)}`);\n if (event.toolName) process.stdout.write(` tool=${event.toolName}`);\n if (event.estimatedCost) process.stdout.write(` cost=${formatCost(event.estimatedCost)}`);\n if (event.tokenCount) process.stdout.write(` tokens=${event.tokenCount}`);\n process.stdout.write('\\n');\n\n const summary = summarizeEvent(event);\n if (summary) process.stdout.write(`${indent(wrap(summary, 88))}\\n`);\n}\n\nfunction summarizeEvent(event: EventSummary): string {\n if (hasMeaningfulValue(event.toolError)) {\n return `Error: ${formatCompactJson(event.toolError)}`;\n }\n if (event.reasoning) {\n return event.reasoning;\n }\n if (hasMeaningfulValue(event.toolOutput)) {\n return `Output: ${formatCompactJson(event.toolOutput)}`;\n }\n if (hasMeaningfulValue(event.toolInput)) {\n return `Input: ${formatCompactJson(event.toolInput)}`;\n }\n return '';\n}\n\nfunction printKeyValues(values: Record<string, unknown>): void {\n const entries = Object.entries(values);\n const width = entries.reduce((max, [key]) => Math.max(max, key.length), 0);\n for (const [key, value] of entries) {\n process.stdout.write(`${key.padEnd(width)} ${String(value)}\\n`);\n }\n}\n\nfunction printJson(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\ninterface TableColumn<T> {\n header: string;\n maxWidth: number;\n render: (row: T) => string;\n}\n\nfunction printTable<T>(rows: T[], columns: Array<TableColumn<T>>): void {\n const widths = columns.map((column) => {\n const max = Math.max(column.header.length, ...rows.map((row) => column.render(row).length));\n return Math.min(max, column.maxWidth);\n });\n\n const header = columns\n .map((column, index) => pad(truncate(column.header, widths[index]), widths[index]))\n .join(' ');\n const divider = widths.map((width) => '-'.repeat(width)).join(' ');\n process.stdout.write(`${header}\\n${divider}\\n`);\n\n for (const row of rows) {\n const line = columns\n .map((column, index) => pad(truncate(column.render(row), widths[index]), widths[index]))\n .join(' ');\n process.stdout.write(`${line}\\n`);\n }\n}\n\nfunction truncate(value: string, width: number): string {\n if (value.length <= width) return value;\n if (width <= 1) return value.slice(0, width);\n return `${value.slice(0, width - 1)}...`.slice(0, width);\n}\n\nfunction pad(value: string, width: number): string {\n return `${value}${' '.repeat(Math.max(0, width - value.length))}`;\n}\n\nfunction color(ctx: CliContext, name: 'cyan' | 'green' | 'red' | 'yellow', value: string): string {\n if (!ctx.color) return value;\n const codes = {\n cyan: 36,\n green: 32,\n red: 31,\n yellow: 33,\n };\n return `\\u001b[${codes[name]}m${value}\\u001b[0m`;\n}\n\nfunction bold(ctx: CliContext, value: string): string {\n return ctx.color ? `\\u001b[1m${value}\\u001b[0m` : value;\n}\n\nfunction severityLabel(ctx: CliContext, severity: DiagnoseFinding['severity']): string {\n if (severity === 'high') return color(ctx, 'red', '[high]');\n if (severity === 'medium') return color(ctx, 'yellow', '[medium]');\n if (severity === 'low') return color(ctx, 'cyan', '[low]');\n return '[info]';\n}\n\nfunction formatResult(success: boolean | null | undefined): string {\n if (success === true) return 'pass';\n if (success === false) return 'fail';\n return '-';\n}\n\nfunction formatNullableNumber(value: number | null | undefined): string {\n return typeof value === 'number' ? String(Math.round(value * 10) / 10) : '-';\n}\n\nfunction formatDuration(ms: number | null | undefined): string {\n if (typeof ms !== 'number') return '-';\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60_000).toFixed(1)}m`;\n}\n\nfunction formatCost(cost: number | null | undefined): string {\n return typeof cost === 'number' ? `$${cost.toFixed(4)}` : '-';\n}\n\nfunction formatDate(value: string | null | undefined): string {\n if (!value) return '-';\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n return date.toISOString().replace('T', ' ').slice(0, 16);\n}\n\nfunction formatCompactJson(value: unknown): string {\n if (value === undefined) return '';\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction wrap(text: string, width = 92): string {\n const words = text.replace(/\\s+/g, ' ').trim().split(' ');\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n if (`${current} ${word}`.trim().length > width && current) {\n lines.push(current);\n current = word;\n } else {\n current = `${current} ${word}`.trim();\n }\n }\n if (current) lines.push(current);\n return lines.join('\\n');\n}\n\nfunction indent(text: string, spaces = 2): string {\n const prefix = ' '.repeat(spaces);\n return text\n .split('\\n')\n .map((line) => `${prefix}${line}`)\n .join('\\n');\n}\n\nexport async function run(argv: string[]): Promise<void> {\n const parsed = parseArgs(argv);\n const ctx = createContext(parsed.flags);\n const [command, ...rest] = parsed.positionals;\n\n if (getBooleanFlag(parsed.flags, 'version')) {\n process.stdout.write(`${CLI_VERSION}\\n`);\n return;\n }\n\n if (!command || getBooleanFlag(parsed.flags, 'help')) {\n process.stdout.write(HELP);\n return;\n }\n\n switch (command) {\n case 'install':\n await commandInstall(ctx, parsed.flags);\n break;\n case 'init':\n await commandInit(ctx, parsed.flags);\n break;\n case 'login':\n await commandLogin(ctx, parsed.flags);\n break;\n case 'sessions':\n await commandSessions(ctx, parsed.flags, rest);\n break;\n case 'events':\n await commandEvents(ctx, parsed.flags, rest);\n break;\n case 'signals':\n await commandSignals(ctx, parsed.flags, rest);\n break;\n case 'diagnose':\n await commandDiagnose(ctx, parsed.flags, rest[0]);\n break;\n case 'evaluate':\n await commandEvaluate(ctx, parsed.flags, rest[0]);\n break;\n case 'clusters':\n case 'fix':\n case 'replay':\n commandReserved(command);\n break;\n default:\n throw new CliError(`Unknown command: ${command}. Run sentrial --help.`);\n }\n}\n\nif (process.env.SENTRIAL_CLI_SKIP_AUTO_RUN !== '1') {\n run(process.argv.slice(2)).catch((error: unknown) => {\n if (error instanceof CliError) {\n if (process.env.SENTRIAL_CLI_DEBUG) {\n process.stderr.write(`${error.stack ?? error.message}\\n`);\n } else {\n process.stderr.write(`Error: ${error.message}\\n`);\n }\n process.exitCode = error.exitCode;\n return;\n }\n\n process.stderr.write(\n `${error instanceof Error ? (error.stack ?? error.message) : String(error)}\\n`\n );\n process.exitCode = 1;\n });\n}\n"],"mappings":"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","names":["packageName"]}
package/dist/index.cjs CHANGED
@@ -15,7 +15,7 @@ var __copyProps = (to, from, except, desc) => {
15
15
  }
16
16
  return to;
17
17
  };
18
- var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
20
  // src/index.ts
21
21
  var index_exports = {};
@@ -48,6 +48,7 @@ __export(index_exports, {
48
48
  getExperimentId: () => getExperimentId,
49
49
  getSessionContext: () => getSessionContext,
50
50
  getSystemPrompt: () => getSystemPrompt,
51
+ getVariant: () => getVariant,
51
52
  getVariantName: () => getVariantName,
52
53
  hashValue: () => hashValue,
53
54
  isExperimentMode: () => isExperimentMode,
@@ -143,7 +144,7 @@ var ValidationError = class extends SentrialError {
143
144
  // src/redact.ts
144
145
  var _createHash;
145
146
  try {
146
- const mod = eval("require")("crypto");
147
+ const mod = new Function('return require("crypto")')();
147
148
  if (mod?.createHash) {
148
149
  _createHash = mod.createHash;
149
150
  }
@@ -248,7 +249,7 @@ function redactPayload(payload, config) {
248
249
  // src/async-context.ts
249
250
  var _AsyncLocalStorage = null;
250
251
  try {
251
- const mod = eval("require")("node:async_hooks");
252
+ const mod = new Function('return require("node:async_hooks")')();
252
253
  if (mod?.AsyncLocalStorage) {
253
254
  _AsyncLocalStorage = mod.AsyncLocalStorage;
254
255
  }
@@ -398,6 +399,9 @@ function getSessionContext() {
398
399
  function setDefaultClient(client) {
399
400
  _defaultClient = client;
400
401
  }
402
+ function getDefaultClient() {
403
+ return _defaultClient;
404
+ }
401
405
  function _setSessionContextWithTokens(sessionId, client) {
402
406
  const _sessionToken = _currentSessionId.set(sessionId);
403
407
  const _clientToken = client ? _currentClient.set(client) : _currentClient.set(_currentClient.get());
@@ -955,7 +959,7 @@ var EventBatcher = class {
955
959
  /**
956
960
  * Flush all queued events to the API.
957
961
  *
958
- * Drains the queue and fires all requests in parallel. Safe to call
962
+ * Drains the queue and sends requests in enqueue order. Safe to call
959
963
  * concurrently — only one flush runs at a time.
960
964
  */
961
965
  async flush() {
@@ -963,15 +967,15 @@ var EventBatcher = class {
963
967
  this.flushing = true;
964
968
  const batch = this.queue.splice(0, this.queue.length);
965
969
  try {
966
- await Promise.all(
967
- batch.map(
968
- (event) => this.sendFn(event.method, event.url, event.body).catch((err) => {
969
- if (typeof console !== "undefined") {
970
- console.warn("Sentrial: Batched event failed:", err);
971
- }
972
- })
973
- )
974
- );
970
+ for (const event of batch) {
971
+ try {
972
+ await this.sendFn(event.method, event.url, event.body);
973
+ } catch (err) {
974
+ if (typeof console !== "undefined") {
975
+ console.warn("Sentrial: Batched event failed:", err);
976
+ }
977
+ }
978
+ }
975
979
  } finally {
976
980
  this.flushing = false;
977
981
  }
@@ -1024,6 +1028,7 @@ var SentrialClient = class {
1024
1028
  piiHydrationPromise;
1025
1029
  _stateVar = createContextVar({});
1026
1030
  batcher;
1031
+ pendingExperimentAssignmentIds = [];
1027
1032
  /** Per-session cost/token accumulator — populated by trackToolCall/trackDecision */
1028
1033
  sessionAccumulators = /* @__PURE__ */ new Map();
1029
1034
  get currentState() {
@@ -1174,12 +1179,12 @@ var SentrialClient = class {
1174
1179
  }
1175
1180
  }
1176
1181
  }
1177
- const networkError = new NetworkError(
1178
- lastError?.message ?? "Unknown network error",
1179
- lastError
1180
- );
1182
+ const networkError = new NetworkError(lastError?.message ?? "Unknown network error", lastError);
1181
1183
  if (this.failSilently) {
1182
- console.warn(`Sentrial: Request failed after ${MAX_RETRIES + 1} attempts (${method} ${url}):`, networkError.message);
1184
+ console.warn(
1185
+ `Sentrial: Request failed after ${MAX_RETRIES + 1} attempts (${method} ${url}):`,
1186
+ networkError.message
1187
+ );
1183
1188
  return null;
1184
1189
  }
1185
1190
  throw networkError;
@@ -1222,13 +1227,53 @@ var SentrialClient = class {
1222
1227
  if (params.convoId) {
1223
1228
  payload.convoId = params.convoId;
1224
1229
  }
1230
+ const experimentAssignmentIds = [
1231
+ ...params.experimentAssignmentIds || [],
1232
+ ...this.pendingExperimentAssignmentIds
1233
+ ];
1234
+ if (experimentAssignmentIds.length > 0) {
1235
+ payload.experimentAssignmentIds = Array.from(new Set(experimentAssignmentIds));
1236
+ payload.metadata = {
1237
+ ...params.metadata || {},
1238
+ sentrial_experiment_assignment_ids: payload.experimentAssignmentIds
1239
+ };
1240
+ }
1225
1241
  const response = await this.safeRequest(
1226
1242
  "POST",
1227
1243
  `${this.apiUrl}/api/sdk/sessions`,
1228
1244
  payload
1229
1245
  );
1246
+ if (response?.id && experimentAssignmentIds.length > 0) {
1247
+ this.pendingExperimentAssignmentIds = [];
1248
+ }
1230
1249
  return response?.id ?? null;
1231
1250
  }
1251
+ /**
1252
+ * Get a sticky production experiment variant for this user/conversation.
1253
+ *
1254
+ * The returned assignment id is automatically linked to the next session
1255
+ * created by this client. You can also pass `sessionId` to link immediately.
1256
+ */
1257
+ async getVariant(params) {
1258
+ const fallback = {
1259
+ active: false,
1260
+ reason: "not_found",
1261
+ variant: params.defaultVariant || "control"
1262
+ };
1263
+ const response = await this.safeRequest(
1264
+ "POST",
1265
+ `${this.apiUrl}/api/sdk/experiments/variant`,
1266
+ {
1267
+ ...params,
1268
+ sdkName: "@sentrial/sdk"
1269
+ }
1270
+ );
1271
+ if (!response) return fallback;
1272
+ if (response.active && response.assignmentId && !params.sessionId) {
1273
+ this.pendingExperimentAssignmentIds.push(response.assignmentId);
1274
+ }
1275
+ return response;
1276
+ }
1232
1277
  /**
1233
1278
  * Track a tool call event
1234
1279
  *
@@ -1337,11 +1382,9 @@ var SentrialClient = class {
1337
1382
  * @returns Updated session or null on error
1338
1383
  */
1339
1384
  async setInput(sessionId, input) {
1340
- return this.safeRequest(
1341
- "PATCH",
1342
- `${this.apiUrl}/api/sdk/sessions/${sessionId}`,
1343
- { userInput: input }
1344
- );
1385
+ return this.safeRequest("PATCH", `${this.apiUrl}/api/sdk/sessions/${sessionId}`, {
1386
+ userInput: input
1387
+ });
1345
1388
  }
1346
1389
  /**
1347
1390
  * Track a generic event
@@ -1401,10 +1444,14 @@ var SentrialClient = class {
1401
1444
  }
1402
1445
  const acc = this.sessionAccumulators.get(params.sessionId);
1403
1446
  if (acc) {
1404
- if (params.estimatedCost === void 0 && acc.cost > 0) params = { ...params, estimatedCost: acc.cost };
1405
- if (params.promptTokens === void 0 && acc.promptTokens > 0) params = { ...params, promptTokens: acc.promptTokens };
1406
- if (params.completionTokens === void 0 && acc.completionTokens > 0) params = { ...params, completionTokens: acc.completionTokens };
1407
- if (params.totalTokens === void 0 && acc.totalTokens > 0) params = { ...params, totalTokens: acc.totalTokens };
1447
+ if (params.estimatedCost === void 0 && acc.cost > 0)
1448
+ params = { ...params, estimatedCost: acc.cost };
1449
+ if (params.promptTokens === void 0 && acc.promptTokens > 0)
1450
+ params = { ...params, promptTokens: acc.promptTokens };
1451
+ if (params.completionTokens === void 0 && acc.completionTokens > 0)
1452
+ params = { ...params, completionTokens: acc.completionTokens };
1453
+ if (params.totalTokens === void 0 && acc.totalTokens > 0)
1454
+ params = { ...params, totalTokens: acc.totalTokens };
1408
1455
  this.sessionAccumulators.delete(params.sessionId);
1409
1456
  }
1410
1457
  const payload = {
@@ -1638,10 +1685,14 @@ function getClient() {
1638
1685
  }
1639
1686
  function configure(config) {
1640
1687
  defaultClient = new SentrialClient(config);
1688
+ setDefaultClient(defaultClient);
1641
1689
  }
1642
1690
  function begin(params) {
1643
1691
  return getClient().begin(params);
1644
1692
  }
1693
+ function getVariant(params) {
1694
+ return getClient().getVariant(params);
1695
+ }
1645
1696
  async function flush() {
1646
1697
  if (defaultClient) await defaultClient.flush();
1647
1698
  }
@@ -1651,11 +1702,16 @@ async function shutdown() {
1651
1702
  var sentrial = {
1652
1703
  configure,
1653
1704
  begin,
1705
+ getVariant,
1654
1706
  flush,
1655
1707
  shutdown
1656
1708
  };
1657
1709
 
1658
1710
  // src/vercel.ts
1711
+ function resolveStringOrFn(value, fallback) {
1712
+ if (typeof value === "function") return value() ?? fallback;
1713
+ return value ?? fallback;
1714
+ }
1659
1715
  var _defaultClient2 = null;
1660
1716
  var _globalConfig = {};
1661
1717
  function configureVercel(config) {
@@ -1664,6 +1720,7 @@ function configureVercel(config) {
1664
1720
  apiUrl: config.apiUrl,
1665
1721
  failSilently: config.failSilently ?? true
1666
1722
  });
1723
+ setDefaultClient(_defaultClient2);
1667
1724
  _globalConfig = {
1668
1725
  defaultAgent: config.defaultAgent,
1669
1726
  userId: config.userId,
@@ -1713,14 +1770,26 @@ function calculateCostForCall(provider, modelId, promptTokens, completionTokens)
1713
1770
  return 0;
1714
1771
  }
1715
1772
  }
1773
+ function extractContentText(content) {
1774
+ if (typeof content === "string") return content;
1775
+ if (Array.isArray(content)) {
1776
+ const textParts = content.filter((part) => part && part.type === "text" && typeof part.text === "string").map((part) => part.text);
1777
+ if (textParts.length > 0) return textParts.join("\n");
1778
+ }
1779
+ return JSON.stringify(content);
1780
+ }
1716
1781
  function extractInput(params) {
1717
1782
  if (params.prompt) return params.prompt;
1718
1783
  if (params.messages && params.messages.length > 0) {
1719
1784
  const lastUserMessage = [...params.messages].reverse().find((m) => m.role === "user");
1720
1785
  if (lastUserMessage) {
1721
- return typeof lastUserMessage.content === "string" ? lastUserMessage.content : JSON.stringify(lastUserMessage.content);
1786
+ return extractContentText(lastUserMessage.content);
1722
1787
  }
1723
- return JSON.stringify(params.messages);
1788
+ const lastNonSystem = [...params.messages].reverse().find((m) => m.role !== "system");
1789
+ if (lastNonSystem) {
1790
+ return extractContentText(lastNonSystem.content);
1791
+ }
1792
+ return "";
1724
1793
  }
1725
1794
  return "";
1726
1795
  }
@@ -1834,8 +1903,8 @@ function wrapGenerateText(originalFn, client, config) {
1834
1903
  const sessionId = await client.createSession({
1835
1904
  name: `generateText: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
1836
1905
  agentName: config.defaultAgent ?? "vercel-ai-sdk",
1837
- userId: config.userId ?? "anonymous",
1838
- convoId: config.convoId,
1906
+ userId: resolveStringOrFn(config.userId, "anonymous"),
1907
+ convoId: resolveStringOrFn(config.convoId),
1839
1908
  metadata: {
1840
1909
  model: modelId,
1841
1910
  provider,
@@ -1935,6 +2004,7 @@ function wrapStreamText(originalFn, client, config) {
1935
2004
  const { modelId, provider } = extractModelInfo(params.model);
1936
2005
  const input = extractInput(params);
1937
2006
  let sessionId = null;
2007
+ let sessionCompleted = false;
1938
2008
  let resolveSessionReady;
1939
2009
  const sessionReady = new Promise((resolve) => {
1940
2010
  resolveSessionReady = resolve;
@@ -1944,8 +2014,8 @@ function wrapStreamText(originalFn, client, config) {
1944
2014
  const id = await client.createSession({
1945
2015
  name: `streamText: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
1946
2016
  agentName: config.defaultAgent ?? "vercel-ai-sdk",
1947
- userId: config.userId ?? "anonymous",
1948
- convoId: config.convoId,
2017
+ userId: resolveStringOrFn(config.userId, "anonymous"),
2018
+ convoId: resolveStringOrFn(config.convoId),
1949
2019
  metadata: {
1950
2020
  model: modelId,
1951
2021
  provider,
@@ -2001,7 +2071,8 @@ function wrapStreamText(originalFn, client, config) {
2001
2071
  },
2002
2072
  onFinish: async (event) => {
2003
2073
  await sessionReady;
2004
- if (sessionId) {
2074
+ if (sessionId && !sessionCompleted) {
2075
+ sessionCompleted = true;
2005
2076
  const durationMs = Date.now() - startTime;
2006
2077
  const usage = normalizeUsage(event.totalUsage ?? event.usage);
2007
2078
  const resolvedModelId = event.response?.modelId ?? modelId;
@@ -2031,7 +2102,8 @@ function wrapStreamText(originalFn, client, config) {
2031
2102
  },
2032
2103
  onError: async (event) => {
2033
2104
  await sessionReady;
2034
- if (sessionId) {
2105
+ if (sessionId && !sessionCompleted) {
2106
+ sessionCompleted = true;
2035
2107
  const durationMs = Date.now() - startTime;
2036
2108
  const msg = event.error?.message ?? "Unknown error";
2037
2109
  await client.trackError({
@@ -2081,8 +2153,8 @@ function wrapGenerateObject(originalFn, client, config) {
2081
2153
  const sessionId = await client.createSession({
2082
2154
  name: `generateObject: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
2083
2155
  agentName: config.defaultAgent ?? "vercel-ai-sdk",
2084
- userId: config.userId ?? "anonymous",
2085
- convoId: config.convoId,
2156
+ userId: resolveStringOrFn(config.userId, "anonymous"),
2157
+ convoId: resolveStringOrFn(config.convoId),
2086
2158
  metadata: {
2087
2159
  model: modelId,
2088
2160
  provider,
@@ -2157,8 +2229,8 @@ function wrapStreamObject(originalFn, client, config) {
2157
2229
  const id = await client.createSession({
2158
2230
  name: `streamObject: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
2159
2231
  agentName: config.defaultAgent ?? "vercel-ai-sdk",
2160
- userId: config.userId ?? "anonymous",
2161
- convoId: config.convoId,
2232
+ userId: resolveStringOrFn(config.userId, "anonymous"),
2233
+ convoId: resolveStringOrFn(config.convoId),
2162
2234
  metadata: {
2163
2235
  model: modelId,
2164
2236
  provider,
@@ -2448,6 +2520,11 @@ function wrapClaudeAgent(queryFn, wrapOptions) {
2448
2520
  var _defaultClient3 = null;
2449
2521
  var _currentInteraction = createContextVar(null);
2450
2522
  function getClient3() {
2523
+ const configuredClient = getDefaultClient();
2524
+ if (configuredClient) {
2525
+ _defaultClient3 = configuredClient;
2526
+ return configuredClient;
2527
+ }
2451
2528
  if (!_defaultClient3) {
2452
2529
  try {
2453
2530
  _defaultClient3 = new SentrialClient();
@@ -3216,6 +3293,7 @@ var Experiment = class {
3216
3293
  getExperimentId,
3217
3294
  getSessionContext,
3218
3295
  getSystemPrompt,
3296
+ getVariant,
3219
3297
  getVariantName,
3220
3298
  hashValue,
3221
3299
  isExperimentMode,