@burdenoff/microfe-vibecontrols 2026.710.1 → 2026.714.1
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/dist/components/agents/AgentForm.js.map +1 -1
- package/dist/components/security/agentClient.js.map +1 -1
- package/dist/components/security/types.js.map +1 -1
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/ScheduledJobDetailPage.js.map +1 -1
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/services/assistantApi.js +34 -248
- package/dist/services/assistantApi.js.map +1 -1
- package/dist/services/createSandboxAssistantTransport.js +11 -114
- package/dist/services/createSandboxAssistantTransport.js.map +1 -1
- package/dist/types/assistant.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistantApi.js","names":[],"sources":["../../src/services/assistantApi.ts"],"sourcesContent":["/**\n * AI Assistant API service.\n *\n * All requests go through the wspace-public-gateway (GraphQL Federation):\n * Frontend → wspace-public-gateway → wspace-sandbox-svc → ai-assistant (K8s pod)\n *\n * Uses the host app's Apollo Client which already points to the gateway.\n */\n\nimport { type ApolloClient } from '@apollo/client';\nimport { print, type DocumentNode } from 'graphql';\nimport type { AssistantArtifact, AssistantMode } from '@/types/assistant';\nimport type { PageContext } from '@/utils/pageContext';\nimport {\n CreateSandboxDocument,\n GetSandboxDocument,\n GetActiveSandboxesDocument,\n ProxySandboxRequestDocument,\n ExtendSandboxTtlDocument,\n CheckAiCreditsDocument,\n ReportAiTokenUsageDocument,\n} from '@/generated/wspace-operations';\n\n// ── Image registry ─────────────────────────────────────────────────\n\nconst HARBOR_REGISTRY = 'burdenoffregistry.azurecr.io';\nconst DEFAULT_IMAGE_TAG = import.meta.env.VITE_APP_ENV === 'prod' ? 'prod' : 'alpha';\nconst GENERAL_IMAGE_TAG = import.meta.env.VITE_APP_ENV === 'prod' ? 'prod' : 'alpha-proxy-auth-v1';\nconst VIBE_PLUGINS_IMAGE_TAG =\n import.meta.env.VITE_APP_ENV === 'prod' ? 'prod' : 'alpha-proxy-auth-v1';\nconst API_CALLS_IMAGE_TAG =\n import.meta.env.VITE_APP_ENV === 'prod' ? 'prod' : 'alpha-delegated-auth-v11';\nconst ASSISTANT_API_AUTH_STRATEGY = 'sandbox-app-client-headers-v1';\n\nfunction getImageTagForMode(mode: AssistantMode): string {\n switch (mode) {\n case 'general':\n return GENERAL_IMAGE_TAG;\n case 'vibe-plugins':\n return VIBE_PLUGINS_IMAGE_TAG;\n // The combined default mode runs in the api-calls image (it can make calls).\n case 'assistant':\n case 'api-calls':\n return API_CALLS_IMAGE_TAG;\n }\n}\n\nfunction getImageForMode(mode: AssistantMode): string {\n // `assistant` reuses the api-calls image — one image, mode selected at runtime\n // via AI_ASSISTANT_MODE. So the image segment is api-calls for both.\n const imageMode = mode === 'assistant' ? 'api-calls' : mode;\n return `${HARBOR_REGISTRY}/wspace/ai-assistant-${imageMode}:${getImageTagForMode(mode)}`;\n}\n\nfunction getResourcesForMode(mode: AssistantMode): {\n cpuRequest: string;\n cpuLimit: string;\n memoryRequest: string;\n memoryLimit: string;\n} {\n switch (mode) {\n case 'general':\n return {\n cpuRequest: '100m',\n cpuLimit: '500m',\n memoryRequest: '256Mi',\n memoryLimit: '1Gi',\n };\n case 'vibe-plugins':\n return {\n cpuRequest: '150m',\n cpuLimit: '750m',\n memoryRequest: '384Mi',\n memoryLimit: '1536Mi',\n };\n case 'assistant':\n case 'api-calls':\n return {\n cpuRequest: '150m',\n cpuLimit: '750m',\n memoryRequest: '384Mi',\n memoryLimit: '1536Mi',\n };\n }\n}\n\nfunction resolveSandboxAssistantMode(sandbox: {\n metadata: Record<string, unknown> | null;\n name?: string | null;\n}): AssistantMode | null {\n const metadataMode = sandbox.metadata?.assistantMode;\n if (\n metadataMode === 'assistant' ||\n metadataMode === 'general' ||\n metadataMode === 'api-calls' ||\n metadataMode === 'vibe-plugins'\n ) {\n return metadataMode;\n }\n\n const name = sandbox.name ?? '';\n if (name.startsWith('ai-assistant-vibe-plugins-')) return 'vibe-plugins';\n if (name.startsWith('ai-assistant-api-calls-')) return 'api-calls';\n if (name.startsWith('ai-assistant-general-')) return 'general';\n if (name.startsWith('ai-assistant-assistant-')) return 'assistant';\n return null;\n}\n\n// ── GraphQL operations (colocated .graphql → generated DocumentNodes) ──\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport interface AssistantPromptResult {\n response: string;\n tokens?: { input: number; output: number };\n artifacts?: AssistantArtifact[];\n}\n\nexport interface AssistantRawMessagePart {\n type?: string;\n text?: string;\n tool?: string;\n state?: {\n status?: string;\n input?: unknown;\n output?: unknown;\n raw?: unknown;\n };\n}\n\nexport interface AssistantRawMessage {\n info?: {\n id?: string;\n role?: string;\n providerID?: string;\n modelID?: string;\n tokens?: { input: number; output: number };\n time?: {\n created?: number;\n completed?: number;\n };\n };\n parts?: AssistantRawMessagePart[];\n}\n\nexport interface AssistantSandboxAuthContext {\n accessToken?: string | null;\n workspaceToken?: string | null;\n userId?: string | null;\n organizationId?: string | null;\n}\n\nexport interface AssistantSessionInfo {\n id: string;\n mode: string;\n}\n\ninterface GraphQLResponse<TData> {\n data?: TData;\n errors?: Array<{ message: string }>;\n}\n\nexport interface DownloadedAssistantArtifact {\n filename: string;\n mimeType: string;\n contentBase64: string;\n}\n\ninterface ProxyResponse {\n proxySandboxRequest: {\n status: number;\n body: Record<string, unknown>;\n };\n}\n\nfunction getGatewayRequestContext(\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): { headers?: Record<string, string> } | undefined {\n const headers: Record<string, string> = {};\n\n if (authContext?.accessToken) {\n headers.authorization = `Bearer ${authContext.accessToken}`;\n }\n\n if (authContext?.workspaceToken) {\n headers['x-workspace-authorization'] = `Bearer ${authContext.workspaceToken}`;\n }\n\n if (workspaceId) {\n headers['x-workspace-id'] = workspaceId;\n }\n\n if (authContext?.userId) {\n headers['x-actor-id'] = authContext.userId;\n headers['x-actor-type'] = 'user';\n }\n\n if (authContext?.organizationId) {\n headers['x-org-id'] = authContext.organizationId;\n }\n\n return Object.keys(headers).length > 0 ? { headers } : undefined;\n}\n\nfunction buildSandboxContextInput(\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Record<string, unknown> {\n return {\n workspaceId,\n ...(authContext?.organizationId\n ? {\n custom: {\n organizationId: authContext.organizationId,\n },\n }\n : {}),\n };\n}\n\nasync function executeSandboxGraphQL<TData>(params: {\n document: DocumentNode;\n variables: Record<string, unknown>;\n workspaceId: string;\n authContext?: AssistantSandboxAuthContext;\n}): Promise<TData> {\n const response = await fetch('/workspaces/graphql', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(getGatewayRequestContext(params.workspaceId, params.authContext)?.headers ?? {}),\n },\n body: JSON.stringify({\n query: print(params.document),\n variables: params.variables,\n }),\n });\n\n const result = (await response.json().catch(() => null)) as GraphQLResponse<TData> | null;\n\n if (!response.ok) {\n // Preserve the HTTP status and parsed body so quota detection works.\n // The wspace public gateway returns 429 + errors[].extensions.code =\n // QUOTA_EXHAUSTED for @usage limits (createSandbox, checkAiCredits, …);\n // a bare `HTTP 429` Error would be invisible to isQuotaExhaustedError.\n const messages = result?.errors?.map((error: { message: string }) => error.message).join(', ');\n const httpError = new Error(messages || `Sandbox GraphQL HTTP ${response.status}`) as Error & {\n statusCode?: number;\n result?: unknown;\n };\n httpError.statusCode = response.status;\n httpError.result = result ?? undefined;\n throw httpError;\n }\n\n if (!result) {\n throw new Error('Sandbox GraphQL returned empty response');\n }\n\n if (result.errors?.length) {\n throw new Error(result.errors.map((error: { message: string }) => error.message).join(', '));\n }\n\n if (!result.data) {\n throw new Error('Sandbox GraphQL returned no data');\n }\n\n return result.data;\n}\n\n// ── Find existing sandbox for a mode ───────────────────────────────\n\nexport async function findExistingSandbox(\n _apollo: ApolloClient,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: AssistantSandboxAuthContext\n): Promise<string | null> {\n const data = await executeSandboxGraphQL<{\n getActiveSandboxes: Array<{\n id: string;\n name: string;\n status: string;\n metadata: Record<string, unknown> | null;\n template: string;\n createdBy: string;\n }>;\n }>({\n document: GetActiveSandboxesDocument,\n variables: { context: buildSandboxContextInput(workspaceId, authContext) },\n workspaceId,\n authContext,\n });\n const sandboxes = data.getActiveSandboxes ?? [];\n\n return (\n sandboxes.find(\n (s) =>\n (s.status === 'RUNNING' || s.status === 'PROVISIONING' || s.status === 'PENDING') &&\n s.template === 'AI_BUILDER' &&\n resolveSandboxAssistantMode(s) === mode &&\n (!authContext?.userId || s.createdBy === authContext.userId) &&\n s.metadata?.authStrategy === ASSISTANT_API_AUTH_STRATEGY &&\n s.metadata?.imageTag === getImageTagForMode(mode)\n )?.id ?? null\n );\n}\n\n// ── Sandbox lifecycle ──────────────────────────────────────────────\n\nexport async function createAssistantSandbox(\n _apollo: ApolloClient,\n mode: AssistantMode,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<string> {\n const resources = getResourcesForMode(mode);\n const env = [\n { name: 'AI_ASSISTANT_MODE', value: mode },\n { name: 'HOSTNAME', value: '0.0.0.0' },\n { name: 'WORKSPACE_ID', value: workspaceId },\n // Product the user is in — drives the agent's dynamic per-product docs fetch\n // (the docs repo is `<product>-docs`). Not a secret. This package is the\n // VibeControls MFE, so the product is vibecontrols; other products' MFEs\n // pass their own id.\n { name: 'AI_ASSISTANT_PRODUCT', value: 'vibecontrols' },\n ];\n\n const data = await executeSandboxGraphQL<{ createSandbox: { id: string } }>({\n document: CreateSandboxDocument,\n variables: {\n input: {\n name: `ai-assistant-${mode}-${Date.now()}`,\n description: `AI Assistant sandbox (${mode} mode)`,\n template: 'AI_BUILDER',\n mode: 'DEPLOYMENT',\n containers: [\n {\n name: 'ai-assistant',\n image: getImageForMode(mode),\n // The agent (start-assistant.sh) binds :8080; the sandbox svc proxies\n // to this declared containerPort, so it MUST be 8080. Declaring 80\n // (the old value) made the proxy connect to a dead port → the sandbox\n // failed provisioning with \"Unable to connect. Is the computer able to\n // access the url?\".\n ports: [{ containerPort: 8080, name: 'http' }],\n env,\n },\n ],\n resources: {\n cpuRequest: resources.cpuRequest,\n cpuLimit: resources.cpuLimit,\n memoryRequest: resources.memoryRequest,\n memoryLimit: resources.memoryLimit,\n },\n ttlSeconds: 600,\n metadata: {\n assistantMode: mode,\n assistantOwnerUserId: authContext?.userId ?? null,\n assistantOrganizationId: authContext?.organizationId ?? null,\n authStrategy: ASSISTANT_API_AUTH_STRATEGY,\n imageTag: getImageTagForMode(mode),\n },\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n },\n workspaceId,\n authContext,\n });\n\n if (!data?.createSandbox?.id) {\n throw new Error('createSandbox returned empty response');\n }\n return data.createSandbox.id;\n}\n\nexport async function waitForSandboxReady(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n maxWaitMs = 300_000,\n onProgress?: (message: string) => void\n): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < maxWaitMs) {\n const data = await executeSandboxGraphQL<{\n getSandbox: { status?: string; errorMessage?: string } | null;\n }>({\n document: GetSandboxDocument,\n variables: { id: sandboxId, context: buildSandboxContextInput(workspaceId, authContext) },\n workspaceId,\n authContext,\n });\n const status = data?.getSandbox?.status;\n const errorMessage = data?.getSandbox?.errorMessage as string | undefined;\n if (status === 'RUNNING') return;\n if (status === 'FAILED' || status === 'STOPPED' || status === 'EXPIRED') {\n throw new Error(\n errorMessage\n ? `Sandbox ${status.toLowerCase()}: ${errorMessage}`\n : `Sandbox ${status.toLowerCase()}`\n );\n }\n const elapsedSeconds = Math.max(1, Math.round((Date.now() - start) / 1000));\n onProgress?.(`Starting assistant environment... (${elapsedSeconds}s)`);\n await new Promise((r) => setTimeout(r, 2000));\n }\n throw new Error('Sandbox startup timed out');\n}\n\n// ── Proxy calls to ai-assistant (via gateway → sandbox-svc) ───────\n\nasync function proxyToSandbox(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n path: string,\n method: string,\n body?: unknown,\n authContext?: AssistantSandboxAuthContext\n): Promise<Record<string, unknown>> {\n const result = await executeSandboxGraphQL<ProxyResponse>({\n document: ProxySandboxRequestDocument,\n variables: {\n input: {\n sandboxId,\n path,\n method,\n body,\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n },\n workspaceId,\n authContext,\n });\n\n const proxyResult = result.proxySandboxRequest;\n if (!proxyResult || proxyResult.status >= 400) {\n const errBody = proxyResult?.body as Record<string, unknown> | undefined;\n throw new Error(\n (errBody?.error as string) ?? `Proxy error: ${proxyResult?.status ?? 'unknown'}`\n );\n }\n\n return proxyResult.body;\n}\n\nexport async function waitForAssistantServiceReady(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n maxWaitMs = 90_000,\n onProgress?: (message: string) => void\n): Promise<void> {\n const startedAt = Date.now();\n\n while (Date.now() - startedAt < maxWaitMs) {\n try {\n await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n '/health',\n 'GET',\n undefined,\n authContext\n );\n return;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (\n !/proxy error: 502|proxy error: 503|proxy error: 404|service not available/i.test(message)\n ) {\n throw error;\n }\n }\n\n const elapsedSeconds = Math.max(1, Math.round((Date.now() - startedAt) / 1000));\n onProgress?.(`Connecting to assistant... (${elapsedSeconds}s)`);\n\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n throw new Error('Assistant service did not become healthy before timeout');\n}\n\n// ── Session management ─────────────────────────────────────────────\n\nexport async function createAssistantSession(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: AssistantSandboxAuthContext\n): Promise<{ sessionId: string }> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n '/sessions',\n 'POST',\n { mode },\n authContext\n );\n const session = body.session as Record<string, unknown>;\n return { sessionId: session.id as string };\n}\n\nexport async function getAssistantSession(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<AssistantSessionInfo> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}`,\n 'GET',\n undefined,\n authContext\n );\n const session = body.session as Record<string, unknown> | undefined;\n\n return {\n id: (session?.id as string | undefined) ?? sessionId,\n mode: (body.mode as string | undefined) ?? 'unknown',\n };\n}\n\n// ── Send prompt ────────────────────────────────────────────────────\n\nexport async function sendAssistantPrompt(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n prompt: string,\n mode: AssistantMode,\n pageContext?: PageContext,\n authContext?: AssistantSandboxAuthContext\n): Promise<AssistantPromptResult> {\n const requestBody = {\n mode,\n prompt,\n pageContext: pageContext\n ? {\n // Keys must match the agent's allowed-context-key contract.\n currentUrl: pageContext.currentUrl,\n currentPage: pageContext.currentPage,\n entityType: pageContext.entityType,\n entityId: pageContext.entityId,\n platform: pageContext.platform,\n version: pageContext.version,\n viewportSize: pageContext.viewportSize,\n }\n : undefined,\n };\n\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/prompt`,\n 'POST',\n requestBody,\n authContext\n );\n\n const message = body.message as Record<string, unknown> | undefined;\n const tokens = message?.tokens as { input: number; output: number } | undefined;\n\n return { response: body.text as string, tokens };\n}\n\nexport async function sendAssistantPromptAsync(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n prompt: string,\n mode: AssistantMode,\n pageContext?: PageContext,\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n const requestBody = {\n mode,\n prompt,\n pageContext: pageContext ?? undefined,\n };\n\n await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/prompt-async`,\n 'POST',\n requestBody,\n authContext\n );\n}\n\nexport async function getAssistantMessages(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext,\n limit = 50\n): Promise<AssistantRawMessage[]> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/messages?limit=${limit}`,\n 'GET',\n undefined,\n authContext\n );\n\n return (body.messages as AssistantRawMessage[] | undefined) ?? [];\n}\n\n// ── AI credits (per-token metering) ────────────────────────────────\n\n/**\n * Pre-flight AI-credit gate. Resolves to `true` when the caller still has\n * AI-credit budget; throws a quota error (HTTP 429 / QUOTA_EXHAUSTED, from\n * the wspace gateway's @usage check) when the monthly token budget is\n * depleted. Detect the rejection with `isQuotaExhaustedError()`.\n */\nexport async function checkAssistantAiCredits(\n _apollo: ApolloClient,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<boolean> {\n const data = await executeSandboxGraphQL<{ checkAiCredits: boolean }>({\n document: CheckAiCreditsDocument,\n variables: {},\n workspaceId,\n authContext,\n });\n return data.checkAiCredits;\n}\n\n/**\n * Post-turn charge. Reports the turn's raw input/output token counts + the\n * model so the svc computes COST-WEIGHTED credits server-side and charges them\n * against `vibecontrols.ai.credits` (the amount is never sent from the client).\n * `messageId` makes the charge idempotent (retries don't double-charge).\n * No-ops when there are no tokens, or when the model is unknown (the charge\n * requires it). Best-effort — callers must not block the displayed answer on it.\n */\nexport async function reportAssistantAiTokenUsage(\n _apollo: ApolloClient,\n workspaceId: string,\n sessionId: string,\n messageId: string,\n model: string | undefined,\n tokens: { input: number; output: number },\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n const inputTokens = Math.max(0, Math.round(tokens.input ?? 0));\n const outputTokens = Math.max(0, Math.round(tokens.output ?? 0));\n if (inputTokens + outputTokens === 0) return;\n // The svc requires a model to price the charge; skip rather than send a turn\n // that can't be priced (the meter under-counts that turn — acceptable).\n if (!model) return;\n\n await executeSandboxGraphQL<{ reportAiTokenUsage: boolean }>({\n document: ReportAiTokenUsageDocument,\n variables: {\n input: { sessionId, messageId, model, inputTokens, outputTokens },\n },\n workspaceId,\n authContext,\n });\n}\n\nexport async function getAssistantArtifacts(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<AssistantArtifact[]> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/artifacts`,\n 'GET',\n undefined,\n authContext\n );\n\n return ((body.artifacts as AssistantArtifact[] | undefined) ?? []).filter(\n (artifact) => !artifact.name.startsWith('.')\n );\n}\n\nexport async function downloadAssistantArtifact(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n artifactPath: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<DownloadedAssistantArtifact> {\n const encodedPath = encodeURIComponent(artifactPath);\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/artifacts/download?path=${encodedPath}`,\n 'GET',\n undefined,\n authContext\n );\n\n const artifact = body.artifact as Record<string, unknown> | undefined;\n if (!artifact) {\n throw new Error('Artifact download returned an empty response');\n }\n\n return {\n filename: artifact.filename as string,\n mimeType: artifact.mimeType as string,\n contentBase64: artifact.contentBase64 as string,\n };\n}\n\n// ── Heartbeat ───────────────────────────────────────────────────────\n\nexport async function sendHeartbeat(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/heartbeat`,\n 'POST',\n undefined,\n authContext\n );\n}\n\nexport async function extendAssistantSandboxTTL(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n additionalSeconds = 600,\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n await executeSandboxGraphQL<{ extendSandboxTTL: { id: string } }>({\n document: ExtendSandboxTtlDocument,\n variables: {\n id: sandboxId,\n additionalSeconds,\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n workspaceId,\n authContext,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"assistantApi.js","names":[],"sources":["../../src/services/assistantApi.ts"],"sourcesContent":["/**\n * AI Assistant API — thin adapter over @burdenoff/fe-libs/shared/assistant.\n *\n * The legacy slide-in panel (AssistantChatArea / AssistantMessageItem /\n * useAssistantHeartbeat) calls these with the historical (apollo-first)\n * signatures. The real implementation now lives once in fe-libs; this file only\n * maps the old signatures onto it, retiring ~775 lines of duplicated logic. The\n * `apollo` argument is vestigial (the shared layer uses graphqlFetch) and is\n * ignored; the product id + prod-runtime + TTL the shared functions need are\n * supplied here.\n */\n\nimport {\n findExistingSandbox as sharedFindExisting,\n createAssistantSandbox as sharedCreate,\n waitForSandboxRunning as sharedWaitRunning,\n waitForAssistantServiceReady as sharedWaitService,\n createAssistantSession as sharedCreateSession,\n getAssistantSession as sharedGetSession,\n sendAssistantPromptAsync as sharedSendAsync,\n getAssistantMessages as sharedGetMessages,\n extendAssistantSandboxTTL as sharedExtendTtl,\n sendHeartbeat as sharedHeartbeat,\n getAssistantArtifacts as sharedGetArtifacts,\n downloadAssistantArtifact as sharedDownloadArtifact,\n checkAssistantAiCredits as sharedCheckCredits,\n reportAssistantAiTokenUsage as sharedReportUsage,\n} from '@burdenoff/fe-libs/shared/assistant';\nimport type {\n AssistantRawMessage as SharedRawMessage,\n AssistantSandboxAuthContext as SharedAuthContext,\n AssistantSessionInfo as SharedSessionInfo,\n DownloadedAssistantArtifact,\n} from '@burdenoff/fe-libs/shared/assistant';\nimport type { AssistantArtifact as LocalAssistantArtifact, AssistantMode } from '@/types/assistant';\nimport type { PageContext } from '@/utils/pageContext';\n\n// Re-export the shared types under the names the panel already imports.\nexport type AssistantRawMessage = SharedRawMessage;\nexport type AssistantSandboxAuthContext = SharedAuthContext;\nexport type AssistantSessionInfo = SharedSessionInfo;\n\n// Vestigial Apollo arg — accepted for signature compatibility, ignored.\ntype ApolloClientLike = unknown;\n\nconst PRODUCT = 'vibecontrols';\n// Matches the original panel behavior: create at 600s, kept warm while open by\n// useAssistantHeartbeat's +600s extend. (The floating widget keeps its own\n// longer-TTL keep-warm via the shared transport.)\nconst DEFAULT_TTL_SECONDS = 600;\n\n// Build-time env parity with the original `assistantApi.ts` image-tag selection\n// (VITE_APP_ENV === 'prod' → prod image tag). Drives getImageTagForMode.\nfunction isProdRuntime(): boolean {\n return import.meta.env.VITE_APP_ENV === 'prod';\n}\n\nconst ctx = (a?: SharedAuthContext): SharedAuthContext => a ?? {};\n\nexport function findExistingSandbox(\n _apollo: ApolloClientLike,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: SharedAuthContext\n): Promise<string | null> {\n return sharedFindExisting(workspaceId, mode, isProdRuntime(), ctx(authContext));\n}\n\nexport function createAssistantSandbox(\n _apollo: ApolloClientLike,\n mode: AssistantMode,\n workspaceId: string,\n authContext?: SharedAuthContext\n): Promise<string> {\n return sharedCreate(\n PRODUCT,\n mode,\n workspaceId,\n isProdRuntime(),\n DEFAULT_TTL_SECONDS,\n ctx(authContext)\n );\n}\n\nexport function waitForSandboxReady(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n authContext?: SharedAuthContext,\n maxWaitMs = 300_000,\n _onProgress?: (message: string) => void\n): Promise<void> {\n return sharedWaitRunning(sandboxId, workspaceId, ctx(authContext), maxWaitMs);\n}\n\nexport function waitForAssistantServiceReady(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n authContext?: SharedAuthContext,\n maxWaitMs = 90_000,\n _onProgress?: (message: string) => void\n): Promise<void> {\n return sharedWaitService(sandboxId, workspaceId, ctx(authContext), maxWaitMs);\n}\n\nexport function createAssistantSession(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: SharedAuthContext\n): Promise<{ sessionId: string }> {\n return sharedCreateSession(sandboxId, workspaceId, mode, ctx(authContext));\n}\n\nexport function getAssistantSession(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: SharedAuthContext\n): Promise<SharedSessionInfo> {\n return sharedGetSession(sandboxId, workspaceId, sessionId, ctx(authContext));\n}\n\nexport function sendAssistantPromptAsync(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n prompt: string,\n mode: AssistantMode,\n pageContext?: PageContext,\n authContext?: SharedAuthContext\n): Promise<{ messageID?: string }> {\n return sharedSendAsync(\n sandboxId,\n workspaceId,\n sessionId,\n prompt,\n mode,\n pageContext as Record<string, unknown> | undefined,\n ctx(authContext)\n );\n}\n\nexport function getAssistantMessages(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: SharedAuthContext,\n limit = 50\n): Promise<SharedRawMessage[]> {\n return sharedGetMessages(sandboxId, workspaceId, sessionId, ctx(authContext), { limit });\n}\n\nexport function checkAssistantAiCredits(\n _apollo: ApolloClientLike,\n workspaceId: string,\n authContext?: SharedAuthContext\n): Promise<boolean> {\n return sharedCheckCredits(workspaceId, ctx(authContext));\n}\n\nexport function reportAssistantAiTokenUsage(\n _apollo: ApolloClientLike,\n workspaceId: string,\n sessionId: string,\n messageId: string,\n model: string | undefined,\n tokens: { input: number; output: number },\n authContext?: SharedAuthContext\n): Promise<void> {\n return sharedReportUsage(workspaceId, sessionId, messageId, model, tokens, ctx(authContext));\n}\n\nexport function getAssistantArtifacts(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: SharedAuthContext\n): Promise<LocalAssistantArtifact[]> {\n // The shared surface widens `type` to `string`; at runtime the agent only ever\n // returns 'file' | 'directory', so the array is structurally the local type.\n return sharedGetArtifacts(sandboxId, workspaceId, sessionId, ctx(authContext)).then(\n (artifacts) => artifacts as unknown as LocalAssistantArtifact[]\n );\n}\n\nexport function downloadAssistantArtifact(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n artifactPath: string,\n authContext?: SharedAuthContext\n): Promise<DownloadedAssistantArtifact> {\n return sharedDownloadArtifact(sandboxId, workspaceId, sessionId, artifactPath, ctx(authContext));\n}\n\nexport function sendHeartbeat(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: SharedAuthContext\n): Promise<void> {\n return sharedHeartbeat(sandboxId, workspaceId, sessionId, ctx(authContext));\n}\n\nexport function extendAssistantSandboxTTL(\n _apollo: ApolloClientLike,\n sandboxId: string,\n workspaceId: string,\n additionalSeconds = 600,\n authContext?: SharedAuthContext\n): Promise<void> {\n return sharedExtendTtl(sandboxId, workspaceId, additionalSeconds, ctx(authContext));\n}\n"],"mappings":";;AA6CA,IAAM,IAAU,gBAIV,IAAsB;AAI5B,SAAS,IAAyB;AAChC,QAAO;;AAGT,IAAM,KAAO,MAA6C,KAAK,EAAE;AAEjE,SAAgB,EACd,GACA,GACA,GACA,GACwB;AACxB,QAAO,EAAmB,GAAa,GAAM,GAAe,EAAE,EAAI,EAAY,CAAC;;AAGjF,SAAgB,EACd,GACA,GACA,GACA,GACiB;AACjB,QAAO,EACL,GACA,GACA,GACA,GAAe,EACf,GACA,EAAI,EAAY,CACjB;;AAGH,SAAgB,EACd,GACA,GACA,GACA,GACA,IAAY,KACZ,GACe;AACf,QAAO,EAAkB,GAAW,GAAa,EAAI,EAAY,EAAE,EAAU;;AAG/E,SAAgB,EACd,GACA,GACA,GACA,GACA,IAAY,KACZ,GACe;AACf,QAAO,EAAkB,GAAW,GAAa,EAAI,EAAY,EAAE,EAAU;;AAG/E,SAAgB,EACd,GACA,GACA,GACA,GACA,GACgC;AAChC,QAAO,EAAoB,GAAW,GAAa,GAAM,EAAI,EAAY,CAAC;;AAG5E,SAAgB,EACd,GACA,GACA,GACA,GACA,GAC4B;AAC5B,QAAO,EAAiB,GAAW,GAAa,GAAW,EAAI,EAAY,CAAC;;AAG9E,SAAgB,EACd,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACiC;AACjC,QAAO,EACL,GACA,GACA,GACA,GACA,GACA,GACA,EAAI,EAAY,CACjB;;AAGH,SAAgB,EACd,GACA,GACA,GACA,GACA,GACA,IAAQ,IACqB;AAC7B,QAAO,EAAkB,GAAW,GAAa,GAAW,EAAI,EAAY,EAAE,EAAE,UAAO,CAAC;;AAG1F,SAAgB,EACd,GACA,GACA,GACkB;AAClB,QAAO,EAAmB,GAAa,EAAI,EAAY,CAAC;;AAG1D,SAAgB,EACd,GACA,GACA,GACA,GACA,GACA,GACA,GACe;AACf,QAAO,EAAkB,GAAa,GAAW,GAAW,GAAO,GAAQ,EAAI,EAAY,CAAC;;AAG9F,SAAgB,EACd,GACA,GACA,GACA,GACA,GACmC;AAGnC,QAAO,EAAmB,GAAW,GAAa,GAAW,EAAI,EAAY,CAAC,CAAC,MAC5E,MAAc,EAChB;;AAGH,SAAgB,EACd,GACA,GACA,GACA,GACA,GACA,GACsC;AACtC,QAAO,EAAuB,GAAW,GAAa,GAAW,GAAc,EAAI,EAAY,CAAC;;AAGlG,SAAgB,EACd,GACA,GACA,GACA,GACA,GACe;AACf,QAAO,EAAgB,GAAW,GAAa,GAAW,EAAI,EAAY,CAAC;;AAG7E,SAAgB,EACd,GACA,GACA,GACA,IAAoB,KACpB,GACe;AACf,QAAO,EAAgB,GAAW,GAAa,GAAmB,EAAI,EAAY,CAAC"}
|
|
@@ -1,120 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { useGatewayClient as f } from "@burdenoff/fe-libs/shared/graphql";
|
|
5
|
-
import { useAuthToken as p } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
1
|
+
import { gatherPageContext as e } from "../utils/pageContext.js";
|
|
2
|
+
import { dispatchAssistantQuotaExhausted as t, notifyAiCreditsUpdated as n } from "../utils/aiCredits.js";
|
|
3
|
+
import { useSandboxAssistantTransport as r } from "@burdenoff/fe-libs/shared/assistant";
|
|
6
4
|
//#region src/services/createSandboxAssistantTransport.ts
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let i = localStorage.getItem(`bf-p-${r}-context`);
|
|
15
|
-
return i ? JSON.parse(i)[e] ?? "" : "";
|
|
16
|
-
} catch {
|
|
17
|
-
return "";
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function y() {
|
|
21
|
-
return new URLSearchParams(window.location.search).get("workspace") ?? v("workspaceId");
|
|
22
|
-
}
|
|
23
|
-
function b() {
|
|
24
|
-
return new URLSearchParams(window.location.search).get("org") ?? v("organizationId");
|
|
25
|
-
}
|
|
26
|
-
function x(e) {
|
|
27
|
-
return e.info?.time?.created ?? 0;
|
|
28
|
-
}
|
|
29
|
-
function S(e) {
|
|
30
|
-
return (e ?? []).filter((e) => e.type === "text" && typeof e.text == "string").map((e) => e.text?.trim() ?? "").filter(Boolean).join("\n");
|
|
31
|
-
}
|
|
32
|
-
function C(e) {
|
|
33
|
-
return (e ?? []).filter((e) => e.type === "tool" && e.tool).map((e) => {
|
|
34
|
-
let t = e.state?.status ?? "running", n = e.tool ?? "tool";
|
|
35
|
-
return t === "completed" ? `Completed: ${n}` : t === "failed" ? `Failed: ${n}` : `Running: ${n}`;
|
|
5
|
+
function i() {
|
|
6
|
+
return r({
|
|
7
|
+
product: "vibecontrols",
|
|
8
|
+
gatherPageContext: e,
|
|
9
|
+
enableCredits: !0,
|
|
10
|
+
onQuotaExhausted: () => t("ai-credits"),
|
|
11
|
+
onCreditsUpdated: () => n()
|
|
36
12
|
});
|
|
37
13
|
}
|
|
38
|
-
function w(e, t) {
|
|
39
|
-
let n = e.filter((e) => e.info?.role === "assistant" && x(e) >= t).sort((e, t) => x(e) - x(t));
|
|
40
|
-
if (n.length === 0) return {
|
|
41
|
-
content: "Thinking…",
|
|
42
|
-
done: !1
|
|
43
|
-
};
|
|
44
|
-
let r = n[n.length - 1], i = S(r.parts), a = C(r.parts);
|
|
45
|
-
return {
|
|
46
|
-
content: [i, ...a].filter(Boolean).join("\n\n") || "Thinking…",
|
|
47
|
-
done: !!r.info?.time?.completed && (!!i || a.length > 0)
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function T(e) {
|
|
51
|
-
return e.replace(/(Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/(X-Workspace-Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+\b/g, "[REDACTED_JWT]").replace(/\bsk-ant-[A-Za-z0-9-]+\b/g, "[REDACTED_API_KEY]");
|
|
52
|
-
}
|
|
53
|
-
function E(e) {
|
|
54
|
-
let t = e instanceof Error ? e.message.toLowerCase() : String(e).toLowerCase();
|
|
55
|
-
return t.includes("rate limit exceeded") || t.includes("unauthorized") || t.includes("k8s api error 401") ? !1 : [
|
|
56
|
-
"sandbox not found",
|
|
57
|
-
"sandbox is not running",
|
|
58
|
-
"sandbox service not available yet",
|
|
59
|
-
"sandbox failed",
|
|
60
|
-
"sandbox startup timed out",
|
|
61
|
-
"assistant service did not become healthy",
|
|
62
|
-
"proxy error: 404",
|
|
63
|
-
"proxy error: 502",
|
|
64
|
-
"proxy error: 503"
|
|
65
|
-
].some((e) => t.includes(e));
|
|
66
|
-
}
|
|
67
|
-
function D() {
|
|
68
|
-
let v = f("workspace"), { getAccessToken: x, getWorkspaceToken: S, userId: C } = p(), D = d(null), O = d(null), k = l(async (n, i) => {
|
|
69
|
-
let a = D.current;
|
|
70
|
-
if (!a) {
|
|
71
|
-
if (a = await r(v, n, m, i), !a) {
|
|
72
|
-
if (!x()) throw Error("API Calls mode requires an authenticated session. Please sign in again.");
|
|
73
|
-
a = await e(v, m, n, i);
|
|
74
|
-
}
|
|
75
|
-
await s(v, a, n, i), await o(v, a, n, i), D.current = a;
|
|
76
|
-
}
|
|
77
|
-
let c = O.current;
|
|
78
|
-
return c || (c = (await t(v, a, n, m, i)).sessionId, O.current = c), {
|
|
79
|
-
sandboxId: a,
|
|
80
|
-
sessionId: c
|
|
81
|
-
};
|
|
82
|
-
}, [v, x]), A = l(async ({ prompt: e, onProgress: t, signal: r }) => {
|
|
83
|
-
let o = y();
|
|
84
|
-
if (!o) throw Error("The assistant needs an active workspace. Open a workspace and try again.");
|
|
85
|
-
let s = {
|
|
86
|
-
accessToken: x(),
|
|
87
|
-
workspaceToken: S(),
|
|
88
|
-
userId: C,
|
|
89
|
-
organizationId: b()
|
|
90
|
-
}, l = async (u) => {
|
|
91
|
-
try {
|
|
92
|
-
let { sandboxId: l, sessionId: u } = await k(o, s), d = Date.now();
|
|
93
|
-
await a(v, l, o, u, e, m, c(), s);
|
|
94
|
-
let f = Date.now() + h, p = Date.now(), y = w([], d);
|
|
95
|
-
for (; Date.now() < f;) {
|
|
96
|
-
if (r.aborted) throw Error("Cancelled");
|
|
97
|
-
if (y = w(await i(v, l, o, u, s, 50), d), t(T(y.content)), y.done) break;
|
|
98
|
-
Date.now() - p > _ && (await n(v, l, o, 600, s).catch(() => void 0), p = Date.now()), await new Promise((e) => setTimeout(e, g));
|
|
99
|
-
}
|
|
100
|
-
if (!y.done) throw Error("The assistant timed out while responding. Please try again.");
|
|
101
|
-
return { text: T(y.content) };
|
|
102
|
-
} catch (e) {
|
|
103
|
-
if (u === 1 && E(e)) return D.current = null, O.current = null, l(2);
|
|
104
|
-
throw e;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
return l(1);
|
|
108
|
-
}, [
|
|
109
|
-
v,
|
|
110
|
-
k,
|
|
111
|
-
x,
|
|
112
|
-
S,
|
|
113
|
-
C
|
|
114
|
-
]);
|
|
115
|
-
return u(() => ({ sendPrompt: A }), [A]);
|
|
116
|
-
}
|
|
117
14
|
//#endregion
|
|
118
|
-
export {
|
|
15
|
+
export { i as useSandboxAssistantTransport };
|
|
119
16
|
|
|
120
17
|
//# sourceMappingURL=createSandboxAssistantTransport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../src/services/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * VibeControls adapter for the shared fe-libs AssistantWidget.\n *\n * The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an\n * injected `AssistantTransport`. This hook builds a transport that reuses the\n * existing sandbox `api-calls` agent (the same backend the Ctrl+Shift+A panel\n * uses): it provisions/reuses a sandbox, opens a session, dispatches the prompt\n * async, then polls for the streamed answer. The agent introspects the GraphQL\n * schema and performs API calls on the user's behalf using their workspace\n * token, contextual to the current screen (via `gatherPageContext`).\n *\n * This is a thin orchestration over the unchanged functions in `assistantApi`.\n */\n\nimport { useCallback, useMemo, useRef } from 'react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n createAssistantSandbox,\n createAssistantSession,\n extendAssistantSandboxTTL,\n findExistingSandbox,\n getAssistantMessages,\n sendAssistantPromptAsync,\n waitForAssistantServiceReady,\n waitForSandboxReady,\n type AssistantRawMessage,\n type AssistantSandboxAuthContext,\n} from './assistantApi';\nimport { gatherPageContext } from '@/utils/pageContext';\nimport type { AssistantMode } from '@/types/assistant';\n\n/**\n * Locally-defined mirror of the fe-libs `AssistantTransport` contract.\n *\n * We intentionally do NOT import the type from `@burdenoff/fe-libs` here:\n * microfe's tsconfig maps `@burdenoff/fe-libs/*` to fe-libs *source*, so\n * vite-plugin-dts would rewrite a cross-package type used in this hook's\n * public signature to a broken source-relative path in the emitted `.d.ts`.\n * Structural typing makes this shape assignable to fe-libs' `AssistantTransport`\n * at the call site (vibecontrols-app's AppShell), which is where compatibility\n * is enforced — drift there fails the app type-check.\n */\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n}\n\nconst MODE: AssistantMode = 'assistant';\nconst STREAM_BUDGET_MS = 180_000;\nconst POLL_INTERVAL_MS = 1500;\nconst TTL_EXTEND_INTERVAL_MS = 30_000;\n\n// ── Context helpers (mirror AssistantChatArea's resolution) ──────────\n\nfunction getProfileContextValue(key: 'workspaceId' | 'organizationId'): string {\n try {\n const activeContextKey =\n key === 'workspaceId'\n ? 'burdenoff-active-context-workspace'\n : 'burdenoff-active-context-organization';\n const activeContextValue = localStorage.getItem(activeContextKey);\n if (activeContextValue) return activeContextValue;\n\n const activeProfileId = sessionStorage.getItem('bf-active-profile');\n if (!activeProfileId) return '';\n const raw = localStorage.getItem(`bf-p-${activeProfileId}-context`);\n if (!raw) return '';\n const context = JSON.parse(raw) as { workspaceId?: string; organizationId?: string };\n return context[key] ?? '';\n } catch {\n return '';\n }\n}\n\nfunction getWorkspaceId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('workspace') ?? getProfileContextValue('workspaceId');\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('org') ?? getProfileContextValue('organizationId');\n}\n\n// ── Message-progress helpers (pure; mirror AssistantChatArea) ────────\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n return message.info?.time?.created ?? 0;\n}\n\nfunction getAssistantText(parts: AssistantRawMessage['parts']): string {\n return (parts ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text?.trim() ?? '')\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction getToolProgress(parts: AssistantRawMessage['parts']): string[] {\n return (parts ?? [])\n .filter((part) => part.type === 'tool' && part.tool)\n .map((part) => {\n const status = part.state?.status ?? 'running';\n const tool = part.tool ?? 'tool';\n if (status === 'completed') return `Completed: ${tool}`;\n if (status === 'failed') return `Failed: ${tool}`;\n return `Running: ${tool}`;\n });\n}\n\nfunction buildProgress(\n messages: AssistantRawMessage[],\n sinceMs: number\n): { content: string; done: boolean } {\n const relevant = messages\n .filter(\n (message) => message.info?.role === 'assistant' && getRawMessageCreatedAt(message) >= sinceMs\n )\n .sort((left, right) => getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right));\n\n if (relevant.length === 0) return { content: 'Thinking…', done: false };\n\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest.parts);\n const toolProgress = getToolProgress(latest.parts);\n const content = [text, ...toolProgress].filter(Boolean).join('\\n\\n') || 'Thinking…';\n\n return {\n content,\n done: Boolean(latest.info?.time?.completed) && (Boolean(text) || toolProgress.length > 0),\n };\n}\n\nfunction sanitize(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g, '[REDACTED_JWT]')\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, '[REDACTED_API_KEY]');\n}\n\nfunction isRecoverable(error: unknown): boolean {\n const message =\n error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n if (\n message.includes('rate limit exceeded') ||\n message.includes('unauthorized') ||\n message.includes('k8s api error 401')\n ) {\n return false;\n }\n return [\n 'sandbox not found',\n 'sandbox is not running',\n 'sandbox service not available yet',\n 'sandbox failed',\n 'sandbox startup timed out',\n 'assistant service did not become healthy',\n 'proxy error: 404',\n 'proxy error: 502',\n 'proxy error: 503',\n ].some((fragment) => message.includes(fragment));\n}\n\n/**\n * Returns a memoized `AssistantTransport` wired to the VibeControls sandbox\n * `api-calls` agent. The sandbox + session are cached in refs so follow-up\n * turns reuse the warm environment for the lifetime of the host shell.\n */\nexport function useSandboxAssistantTransport(): AssistantTransport {\n const apollo = useGatewayClient('workspace');\n const { getAccessToken, getWorkspaceToken, userId } = useAuthToken();\n\n const sandboxIdRef = useRef<string | null>(null);\n const sessionIdRef = useRef<string | null>(null);\n\n const ensureRuntime = useCallback(\n async (\n workspaceId: string,\n authContext: AssistantSandboxAuthContext\n ): Promise<{ sandboxId: string; sessionId: string }> => {\n let sandboxId = sandboxIdRef.current;\n if (!sandboxId) {\n sandboxId = await findExistingSandbox(apollo, workspaceId, MODE, authContext);\n if (!sandboxId) {\n if (!getAccessToken()) {\n throw new Error(\n 'API Calls mode requires an authenticated session. Please sign in again.'\n );\n }\n sandboxId = await createAssistantSandbox(apollo, MODE, workspaceId, authContext);\n }\n await waitForSandboxReady(apollo, sandboxId, workspaceId, authContext);\n await waitForAssistantServiceReady(apollo, sandboxId, workspaceId, authContext);\n sandboxIdRef.current = sandboxId;\n }\n\n let sessionId = sessionIdRef.current;\n if (!sessionId) {\n const result = await createAssistantSession(\n apollo,\n sandboxId,\n workspaceId,\n MODE,\n authContext\n );\n sessionId = result.sessionId;\n sessionIdRef.current = sessionId;\n }\n\n return { sandboxId, sessionId };\n },\n [apollo, getAccessToken]\n );\n\n const sendPrompt = useCallback(\n async ({ prompt, onProgress, signal }: AssistantSendArgs): Promise<{ text: string }> => {\n const workspaceId = getWorkspaceId();\n if (!workspaceId) {\n throw new Error('The assistant needs an active workspace. Open a workspace and try again.');\n }\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n\n const run = async (attempt: 1 | 2): Promise<{ text: string }> => {\n try {\n const { sandboxId, sessionId } = await ensureRuntime(workspaceId, authContext);\n\n const startedAt = Date.now();\n await sendAssistantPromptAsync(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n prompt,\n MODE,\n gatherPageContext(),\n authContext\n );\n\n const timeoutAt = Date.now() + STREAM_BUDGET_MS;\n let lastTtlExtensionAt = Date.now();\n let progress = buildProgress([], startedAt);\n\n while (Date.now() < timeoutAt) {\n if (signal.aborted) throw new Error('Cancelled');\n\n const messages = await getAssistantMessages(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n authContext,\n 50\n );\n progress = buildProgress(messages, startedAt);\n onProgress(sanitize(progress.content));\n if (progress.done) break;\n\n if (Date.now() - lastTtlExtensionAt > TTL_EXTEND_INTERVAL_MS) {\n await extendAssistantSandboxTTL(\n apollo,\n sandboxId,\n workspaceId,\n 600,\n authContext\n ).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n\n if (!progress.done) {\n throw new Error('The assistant timed out while responding. Please try again.');\n }\n\n return { text: sanitize(progress.content) };\n } catch (error) {\n // A stale/expired sandbox or session is recoverable — drop the warm\n // refs and retry once from a clean runtime.\n if (attempt === 1 && isRecoverable(error)) {\n sandboxIdRef.current = null;\n sessionIdRef.current = null;\n return run(2);\n }\n throw error;\n }\n };\n\n return run(1);\n },\n [apollo, ensureRuntime, getAccessToken, getWorkspaceToken, userId]\n );\n\n return useMemo<AssistantTransport>(() => ({ sendPrompt }), [sendPrompt]);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../src/services/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * VibeControls adapter for the shared fe-libs AssistantWidget transport.\n *\n * The entire sandbox lifecycle + poll/stream loop now lives in\n * `@burdenoff/fe-libs/shared/assistant` (one implementation for all products).\n * This file is a thin wrapper that passes the product id, VibeControls'\n * `gatherPageContext`, and its credit-UX callbacks.\n *\n * NOTE: the exported name/shape are unchanged so app-shell imports don't move.\n * The public return type is a LOCALLY-declared structural mirror — we never\n * re-export fe-libs types here (microfe tsconfig maps `@burdenoff/fe-libs/*` to\n * source, and vite-plugin-dts would rewrite a cross-package type in this hook's\n * emitted `.d.ts` to a broken source-relative path).\n */\n\nimport { useSandboxAssistantTransport as useSharedTransport } from '@burdenoff/fe-libs/shared/assistant';\nimport { gatherPageContext } from '@/utils/pageContext';\nimport { dispatchAssistantQuotaExhausted, notifyAiCreditsUpdated } from '@/utils/aiCredits';\n\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n prewarm?: (level?: 'probe' | 'full') => void;\n suspend?: () => void;\n}\n\nexport function useSandboxAssistantTransport(): AssistantTransport {\n return useSharedTransport({\n product: 'vibecontrols',\n gatherPageContext,\n enableCredits: true,\n onQuotaExhausted: () => dispatchAssistantQuotaExhausted('ai-credits'),\n onCreditsUpdated: () => notifyAiCreditsUpdated(),\n });\n}\n"],"mappings":";;;;AA+BA,SAAgB,IAAmD;AACjE,QAAO,EAAmB;EACxB,SAAS;EACT;EACA,eAAe;EACf,wBAAwB,EAAgC,aAAa;EACrE,wBAAwB,GAAwB;EACjD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant.js","names":[],"sources":["../../src/types/assistant.ts"],"sourcesContent":["/**\n * AI Assistant types.\n *\n * Defines the data model for the right-pane AI assistant panel.\n * Interface shapes align with aiApi.ts (AISession, AISessionLog), which is\n * the real workspace gateway backed assistant contract.\n */\n\nimport { ASSISTANT_USECASE_CONFIG, type AssistantUsecaseId } from '@/config/assistantUsecases';\n\nexport type AssistantMode = AssistantUsecaseId;\n\nexport type AssistantSandboxStatus = 'none' | 'provisioning' | 'running' | 'stopping' | 'error';\n\nexport type AssistantConversationStatus =\n
|
|
1
|
+
{"version":3,"file":"assistant.js","names":[],"sources":["../../src/types/assistant.ts"],"sourcesContent":["/**\n * AI Assistant types.\n *\n * Defines the data model for the right-pane AI assistant panel.\n * Interface shapes align with aiApi.ts (AISession, AISessionLog), which is\n * the real workspace gateway backed assistant contract.\n */\n\nimport { ASSISTANT_USECASE_CONFIG, type AssistantUsecaseId } from '@/config/assistantUsecases';\n\nexport type AssistantMode = AssistantUsecaseId;\n\nexport type AssistantSandboxStatus = 'none' | 'provisioning' | 'running' | 'stopping' | 'error';\n\nexport type AssistantConversationStatus =\n 'idle' | 'provisioning' | 'connecting' | 'streaming' | 'complete' | 'error';\n\nexport interface AssistantArtifact {\n name: string;\n path: string;\n type: 'file' | 'directory';\n size: number;\n downloadPath?: string;\n}\n\nexport interface AssistantMessageMetadata {\n artifacts?: AssistantArtifact[];\n mode?: AssistantMode;\n sandboxId?: string;\n sessionId?: string;\n [key: string]: unknown;\n}\n\nexport interface Message {\n id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n timestamp: string;\n tokens?: { input: number; output: number };\n metadata?: AssistantMessageMetadata;\n}\n\nexport interface Conversation {\n id: string;\n title: string;\n mode: AssistantMode;\n messages: Message[];\n createdAt: string;\n updatedAt: string;\n /** Backend session ID for this conversation */\n backendSessionId?: string | null;\n}\n\nexport interface AssistantSandboxRuntime {\n sandboxId: string;\n status: AssistantSandboxStatus;\n}\n\nexport interface AssistantConversationProcessing {\n status: AssistantConversationStatus;\n messageId: string | null;\n error?: string | null;\n updatedAt: string;\n}\n\nexport interface AssistantModeConfig {\n id: AssistantMode;\n label: string;\n description: string;\n suggestions: readonly string[];\n}\n\nexport const ASSISTANT_MODES: AssistantModeConfig[] = [...ASSISTANT_USECASE_CONFIG];\n"],"mappings":";;AAwEA,IAAa,IAAyC,CAAC,GAAG,EAAyB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-vibecontrols",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.714.1",
|
|
4
4
|
"description": "VibeControls microfrontend for Burdenoff products",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"license": "PROPRIETARY",
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@apollo/client": "4.1.9",
|
|
62
|
-
"@burdenoff/fe-libs": "2026.
|
|
62
|
+
"@burdenoff/fe-libs": "2026.714.1",
|
|
63
63
|
"@tanstack/react-query": "^5.90.16",
|
|
64
64
|
"@xyflow/react": "^12.10.2",
|
|
65
65
|
"clsx": "^2.1.1",
|