@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.
- package/README.md +72 -21
- package/dist/cli.cjs +1139 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +77 -0
- package/dist/cli.d.ts +77 -0
- package/dist/cli.js +1100 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +117 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -8
- package/dist/index.d.ts +69 -8
- package/dist/index.js +115 -38
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/cli.js.map
ADDED
|
@@ -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 = (
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
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(
|
|
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
|
-
|
|
1342
|
-
|
|
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)
|
|
1405
|
-
|
|
1406
|
-
if (params.
|
|
1407
|
-
|
|
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
|
|
1786
|
+
return extractContentText(lastUserMessage.content);
|
|
1722
1787
|
}
|
|
1723
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|