dsh-agy 0.2.8 → 0.2.9

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/lib/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { d as isAgyDisabled } from "./accounts-Um8N9I56.mjs";
2
- import { t as createAgyRuntime } from "./plugin-common-DHQVJtXd.mjs";
2
+ import { t as createAgyRuntime } from "./plugin-common-Di4n-1eR.mjs";
3
3
  //#region src/index.ts
4
4
  const name = "dsh-agy";
5
5
  const inject = ["llm"];
@@ -179,12 +179,6 @@ var AgyAdapter = class extends LlmAdapter {
179
179
  async resolveModel(provider, model) {
180
180
  return resolveAgyModel(provider, model);
181
181
  }
182
- async prepareCall(provider, model, _signal) {
183
- return {
184
- model: await this.resolveModel(provider, model),
185
- stream: (options) => this.stream(options)
186
- };
187
- }
188
182
  /**
189
183
  * Pre-resolve every image attachment into base64 bytes before translation.
190
184
  * Image input hard-fails with UNSUPPORTED_CONTENT (terminal, never retried)
@@ -370,4 +364,4 @@ async function createAgyRuntime(ctx) {
370
364
  //#endregion
371
365
  export { createAgyRuntime as t };
372
366
 
373
- //# sourceMappingURL=plugin-common-DHQVJtXd.mjs.map
367
+ //# sourceMappingURL=plugin-common-Di4n-1eR.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-common-Di4n-1eR.mjs","names":[],"sources":["../src/runtime/classify.ts","../src/adapter/adapter.ts","../src/plugin-common.ts"],"sourcesContent":["/**\n * Upstream failure classification: HTTP status + headers + body → FailureKind.\n * Conservative by design: only auth-failure may revoke an account; everything\n * else cools, rotates, or retries.\n */\n\nimport type { FailureKind } from '../types.ts'\nimport { isProxyUnreachableError } from '../proxy.ts'\n\nexport interface ClassifiedError {\n kind: FailureKind\n status?: number\n /** Server-provided retry delay (ms), when the response carried it. */\n retryAfterMs?: number\n /** Server-provided absolute reset time, when the response carried it. */\n resetTime?: string\n message?: string\n /** 429 sub-category, present when kind is rate-limit. */\n rateLimitCategory?: RateLimitCategory\n}\n\n/**\n * 429 sub-category (mirrors CLIProxyAPI/OmniRoute's classify429):\n * - soft_rate_limit: transient burst, retry immediately on the same account\n * - rate_limited: per-minute limit, short cooldown then retry (same account\n * when there is no other)\n * - quota_exhausted: daily/plan quota gone, long cooldown (24h)\n * - unknown: exponential backoff\n */\nexport type RateLimitCategory = 'soft_rate_limit' | 'rate_limited' | 'quota_exhausted' | 'unknown'\n\nconst QUOTA_EXHAUSTED_KEYWORDS = [\n 'quota_exhausted',\n 'quota exhausted',\n 'quota reached',\n 'enable overages',\n 'individual quota',\n]\n\n/** Classify a 429 body into the four upstream categories. */\nexport function classifyRateLimit(\n bodyText: string | undefined,\n retryAfterMs: number | undefined,\n): RateLimitCategory {\n const text = (bodyText ?? '').toLowerCase()\n if (QUOTA_EXHAUSTED_KEYWORDS.some((keyword) => text.includes(keyword))) {\n return 'quota_exhausted'\n }\n if (retryAfterMs !== undefined && retryAfterMs < 3000) {\n return 'soft_rate_limit'\n }\n if (retryAfterMs !== undefined) {\n return 'rate_limited'\n }\n // No explicit retry hint: \"quota\" wording → daily quota, otherwise unknown.\n return text.includes('quota') || text.includes('resource_exhausted') ? 'quota_exhausted' : 'unknown'\n}\n\nconst RATE_LIMIT_RESET_FIELDS = ['resetTime', 'reset_time', 'resetAt', 'quotaResetTime'] as const\n\nfunction extractResetTime(bodyText: string | undefined): string | undefined {\n if (!bodyText) return undefined\n try {\n const data = JSON.parse(bodyText) as Record<string, unknown>\n for (const field of RATE_LIMIT_RESET_FIELDS) {\n const value = data[field]\n if (typeof value === 'string' && value) return value\n if (typeof value === 'number' && Number.isFinite(value)) {\n // Unix ms when large, seconds when small (relative to now).\n return value > 1_000_000_000_000 ? new Date(value).toISOString() : new Date(Date.now() + value * 1000).toISOString()\n }\n }\n const quotaInfo = data.quotaInfo as Record<string, unknown> | undefined\n if (quotaInfo && typeof quotaInfo.resetTime === 'string') return quotaInfo.resetTime\n } catch {\n // not JSON — no reset info\n }\n return undefined\n}\n\nfunction parseRetryAfter(header: string | null): number | undefined {\n if (!header) return undefined\n const seconds = Number(header)\n if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000\n const date = Date.parse(header)\n if (!Number.isNaN(date)) return Math.max(0, date - Date.now())\n return undefined\n}\n\n/** Classify a completed HTTP response (non-2xx). */\nexport function classifyHttpError(\n status: number,\n headers: Headers,\n bodyText?: string,\n): ClassifiedError {\n const retryAfterMs = parseRetryAfter(headers.get('retry-after'))\n const resetTime = extractResetTime(bodyText)\n\n if (status === 429) {\n const category = classifyRateLimit(bodyText, retryAfterMs)\n return {\n kind: 'rate-limit',\n rateLimitCategory: category,\n status,\n retryAfterMs,\n resetTime,\n message: bodyText ? bodyText.slice(0, 200) : undefined,\n }\n }\n if (status === 401) {\n return { kind: 'auth-failure', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n if (status === 403) {\n // Google also reports quota walls as 403 RESOURCE_EXHAUSTED, and the\n // endpoint fallback chain ends on hosts answering 403 for \"no license\"\n // (not bad auth). Only treat a 403 as auth-failure when the body carries\n // no quota wording — a false revoke permanently disables the account.\n const category = classifyRateLimit(bodyText, undefined)\n if (category === 'quota_exhausted') {\n return {\n kind: 'rate-limit',\n rateLimitCategory: category,\n status,\n message: bodyText ? bodyText.slice(0, 200) : undefined,\n }\n }\n return { kind: 'auth-failure', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n if (status === 404) {\n // Model/route missing — nothing to rotate for; surface as transient request error.\n return { kind: 'transient', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n if (status >= 500) {\n return { kind: 'transient', status, retryAfterMs, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n if (status === 400) {\n // A 400 is a request-construction error (permanent — retrying sends the\n // same broken payload). Only capacity-style phrases are recoverable\n // (context overflow / model unavailable), mirroring OmniRoute's\n // classifyProviderError: everything else surfaces as a terminal\n // request-error so rotation does not waste attempts.\n const text = (bodyText ?? '').toLowerCase()\n const recoverable = (\n (text.includes('context') && (text.includes('overflow') || text.includes('too long') || text.includes('exceeded')))\n || (text.includes('model') && (text.includes('not found') || text.includes('unavailable') || text.includes('not supported')))\n )\n if (recoverable) {\n return { kind: 'transient', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n return { kind: 'request-error', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n // 400-range others (401 handled above): request-level errors, no rotation semantics.\n return { kind: 'transient', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n}\n\n/** Classify a fetch-level failure (DNS, refused, timeout, abort). */\nexport function classifyFetchError(error: unknown): ClassifiedError {\n const message = error instanceof Error ? error.message : String(error)\n if (error instanceof DOMException && error.name === 'AbortError') {\n return { kind: 'network-error', message }\n }\n if (isProxyUnreachableError(error)) {\n return { kind: 'proxy-unreachable', message }\n }\n return { kind: 'network-error', message }\n}\n\n/** Classify the result of a refresh attempt (shared by adapter + verify paths). */\nexport function classifyRefreshFailure(status: number, code?: string): ClassifiedError {\n if (code === 'invalid_grant') return { kind: 'auth-failure', status, message: code }\n if (status === 429) return { kind: 'rate-limit', status, message: code }\n if (status >= 500) return { kind: 'transient', status, message: code }\n return { kind: 'transient', status, message: code }\n}\n\nexport type { FailureKind }\n","/**\n * AgyAdapter: the DSH seam. A thin orchestrator over the deep modules —\n * account session resolution (shell-provided), request translation, SSE\n * parsing, failure classification, and rotation reporting. All wire details\n * live in translate.ts / parse.ts / models.ts.\n */\n\nimport {\n LlmAdapter,\n LlmError,\n ProviderRequestId,\n QUOTA_EXCEEDED_CODE,\n attributionHeaders,\n} from '@deepseek-ai/dsh-llm'\nimport type {\n GenerateOptions,\n LlmModelInfo,\n LlmProviderInfo,\n LlmResolvedModelInfo,\n StreamChunk,\n ToolSchema,\n} from '@deepseek-ai/dsh-llm'\n\nimport { AgyAuthError, AgyPoolBlockedError } from '../types.ts'\nimport type { AgyAccountSession, FailureKind, ManagedAccount, OAuthAuthDetails } from '../types.ts'\nimport type { RateLimitCategory } from '../runtime/classify.ts'\nimport { fetchAgyFirstOk } from '../oauth/constants.ts'\nimport { classifyFetchError, classifyHttpError } from '../runtime/classify.ts'\nimport { deriveAntigravitySessionId, generateAntigravityRequestId } from '../runtime/identity.ts'\nimport { setThoughtSignature } from '../runtime/signature-cache.ts'\nimport { toAgyRequestBody } from './translate.ts'\nimport type { AgyResolvedImage } from './translate.ts'\nimport { resolveMultimodalFiles } from './multimodal.ts'\nimport { parseAgySse } from './parse.ts'\nimport { AGY_PROVIDER, catalogModelList, listAgyModels, resolveAgyModel } from './models.ts'\n\nexport type { AgyAccountSession }\n\n/**\n * Structural view of the harness attachment service (ctx.attachments).\n * Deliberately not an import of @deepseek-ai/dsh-attachment: the CLI bundle\n * must stay free of harness runtime dependencies, and the real store\n * satisfies this shape.\n */\nexport interface AgyAttachmentStore {\n readImage(ref: {\n attachmentId: string\n mediaType: string\n }): Promise<{ ref: { mediaType: string }; data: Uint8Array }>\n}\n\n/** Collect image refs from user-message content only (spec scope: user images; tool-result nesting out of scope). */\nfunction collectImageRefs(options: GenerateOptions): Array<{ attachmentId: string; mediaType: string }> {\n const refs: Array<{ attachmentId: string; mediaType: string }> = []\n for (const message of options.messages) {\n if (message.role !== 'user') continue\n for (const block of message.content) {\n if (block.type === 'image') refs.push(block.attachment)\n }\n }\n return refs\n}\n\nexport interface AgyAdapterOptions {\n /** Resolve the active account for a request (model-aware: family-scoped quota ranking). */\n getSession(model?: string): Promise<AgyAccountSession | undefined>\n /** Report a classified upstream failure so the shell can cool/rotate/revoke. */\n reportFailure(\n kind: FailureKind,\n session: AgyAccountSession,\n info?: {\n retryAfterMs?: number\n status?: number\n rateLimitCategory?: RateLimitCategory\n /** Server-reported absolute reset time; drives precise cooldowns. */\n resetTime?: string\n /** Requested model id; drives family-scoped rate-limit bookkeeping. */\n model?: string\n },\n ): Promise<void>\n /** Report a clean stream completion (resets the failure counter). */\n markSuccess?(session: AgyAccountSession): Promise<void>\n /** Resolve the harness attachment store; undefined outside the harness (standalone CLI). */\n resolveAttachments?(): AgyAttachmentStore | undefined\n}\n\nconst UPSTREAM_ERROR_CODE = 'UPSTREAM'\n/** First-class DSH retryable code: the default retry policy honors SERVER (5xx), not UPSTREAM. */\nconst SERVER_ERROR_CODE = 'SERVER'\n\n/** Build the impersonation headers for one request (per-request randomization applied by the shell). */\nexport function buildRequestHeaders(session: AgyAccountSession): Record<string, string> {\n return {\n authorization: `Bearer ${session.auth.access}`,\n 'content-type': 'application/json',\n accept: 'text/event-stream',\n 'x-goog-request-id': generateAntigravityRequestId(),\n ...attributionHeaders(),\n ...session.impersonation,\n }\n}\n\nexport class AgyAdapter extends LlmAdapter {\n private readonly options: AgyAdapterOptions\n\n constructor(options: AgyAdapterOptions) {\n super()\n this.options = options\n }\n\n override providerInfo(_provider: string): LlmProviderInfo {\n return { id: AGY_PROVIDER, name: 'Antigravity (agy)' }\n }\n\n override async listModels(_provider: string): Promise<readonly LlmModelInfo[]> {\n try {\n const session = await this.options.getSession()\n return await listAgyModels(session?.auth.access, session?.account.projectId)\n } catch (error) {\n if (error instanceof AgyPoolBlockedError || error instanceof AgyAuthError) {\n return catalogModelList()\n }\n throw error\n }\n }\n\n override async resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo> {\n return resolveAgyModel(provider, model)\n }\n\n // `prepareCall` is deliberately NOT overridden: the LlmAdapter base class\n // (dsh-llm 0.1.1-rc.2+) already binds the resolved model to the stream, which\n // is exactly what this adapter would do. The base implementation also\n // forwards the cancellation signal, which the previous hand-written copy\n // dropped. Only dynamic adapters — those needing different capabilities per\n // generation — should override it.\n\n /**\n * Pre-resolve every image attachment into base64 bytes before translation.\n * Image input hard-fails with UNSUPPORTED_CONTENT (terminal, never retried)\n * when the store is missing or a read fails — silently dropping images and\n * sending text-only is the exact failure mode this path exists to prevent.\n */\n private async resolveRequestImages(options: GenerateOptions): Promise<Map<string, AgyResolvedImage>> {\n const refs = collectImageRefs(options)\n const images = new Map<string, AgyResolvedImage>()\n if (refs.length === 0) return images\n const store = this.options.resolveAttachments?.()\n if (!store) {\n throw new LlmError(\n 'agy image input requires the durable attachment service (in-harness plugin only)',\n 'UNSUPPORTED_CONTENT',\n )\n }\n // Read every attachment concurrently (N images cost one round-trip, not N).\n // allSettled rather than all: more than one read may reject, and the\n // surfaced error must be deterministic (first failure in ref order) instead\n // of whichever concurrent read happened to reject first — and no rejection\n // may escape as unhandled.\n const settled = await Promise.allSettled(\n refs.map(async (ref) => {\n const stored = await store.readImage(ref)\n return {\n attachmentId: ref.attachmentId,\n image: {\n mediaType: stored.ref.mediaType,\n data: Buffer.from(stored.data).toString('base64'),\n },\n }\n }),\n )\n const failedIndex = settled.findIndex((outcome) => outcome.status === 'rejected')\n if (failedIndex !== -1) {\n const ref = refs[failedIndex]!\n const cause: unknown = (settled[failedIndex] as PromiseRejectedResult).reason\n throw new LlmError(\n `agy image attachment \"${ref.attachmentId}\" could not be loaded: ${cause instanceof Error ? cause.message : String(cause)}`,\n 'UNSUPPORTED_CONTENT',\n { cause: cause instanceof Error ? cause : undefined },\n )\n }\n for (const outcome of settled) {\n if (outcome.status === 'fulfilled') {\n images.set(outcome.value.attachmentId, outcome.value.image)\n }\n }\n return images\n }\n\n override async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {\n // Spec D1 sequence: resolve images first — a locally-failing image request\n // must surface UNSUPPORTED_CONTENT (user story 8) instead of being masked\n // by account-pool errors, and must not touch pool state at all.\n const images = await this.resolveRequestImages(options)\n let session: AgyAccountSession | undefined\n try {\n session = await this.options.getSession(options.model)\n } catch (error) {\n if (error instanceof AgyAuthError) {\n if (error.kind === 'transport') {\n throw new LlmError(error.message, 'TRANSPORT', { cause: error })\n }\n if (error.kind === 'rate-limit') {\n throw new LlmError(error.message, 'RATE_LIMIT', {\n requestId: ProviderRequestId(generateAntigravityRequestId()),\n })\n }\n throw new LlmError(error.message, 'INVALID_CREDENTIAL', { cause: error })\n }\n if (error instanceof AgyPoolBlockedError) {\n if (error.kind === 'quota-exhausted') {\n throw new LlmError(error.message, QUOTA_EXCEEDED_CODE)\n }\n const delta = Math.ceil(error.blockedUntil - Date.now())\n const providerRetryAfterMs = Number.isFinite(delta) && delta > 0 ? delta : 1\n throw new LlmError(error.message, 'RATE_LIMIT', {\n providerRetryAfterMs,\n requestId: ProviderRequestId(generateAntigravityRequestId()),\n })\n }\n throw error\n }\n if (!session) {\n throw new LlmError(\n 'No agy account configured — run `dsh-agy login` to authenticate.',\n 'NO_CREDENTIAL',\n )\n }\n\n const multimodalFiles = await resolveMultimodalFiles(options)\n const body = toAgyRequestBody(options, {\n projectId: session.account.projectId,\n sessionId: deriveAntigravitySessionId(session.account.email) ?? undefined,\n ...(images.size > 0 ? { images } : {}),\n ...(multimodalFiles.size > 0 ? { multimodalFiles } : {}),\n })\n const headers = buildRequestHeaders(session)\n\n let response: Response\n try {\n response = await fetchAgyFirstOk('/v1internal:streamGenerateContent?alt=sse', {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: options.signal,\n })\n } catch (error) {\n const classified = classifyFetchError(error)\n await this.options.reportFailure(classified.kind, session)\n throw new LlmError(classified.message ?? 'agy fetch failed', 'TRANSPORT', { cause: error })\n }\n\n if (!response.ok) {\n const bodyText = await response.text().catch(() => undefined)\n const classified = classifyHttpError(response.status, response.headers, bodyText)\n await this.options.reportFailure(classified.kind, session, {\n retryAfterMs: classified.retryAfterMs,\n status: response.status,\n rateLimitCategory: classified.rateLimitCategory,\n resetTime: classified.resetTime,\n model: options.model,\n })\n if (classified.kind === 'rate-limit') {\n // soft/rate limits are retryable by the harness (RATE_LIMIT + delay);\n // daily quota exhaustion is terminal (QUOTA, 24h cooldown already set).\n if (classified.rateLimitCategory === 'quota_exhausted') {\n throw new LlmError(\n `agy daily quota exhausted (${response.status}): ${classified.message ?? ''}`,\n QUOTA_EXCEEDED_CODE,\n )\n }\n throw new LlmError(\n `agy rate-limited (${response.status}): ${classified.message ?? ''}`,\n 'RATE_LIMIT',\n {\n providerRetryAfterMs: classified.retryAfterMs ?? undefined,\n requestId: ProviderRequestId(generateAntigravityRequestId()),\n },\n )\n }\n if (classified.kind === 'auth-failure') {\n throw new LlmError(\n `agy authentication failed (${response.status}) — run \\`dsh-agy login\\``,\n 'INVALID_CREDENTIAL',\n )\n }\n // 5xx upstream failures (e.g. 503 \"No capacity available\") are transient:\n // the DSH retry policy honors SERVER but treats UPSTREAM as terminal, so\n // classifying 5xx as UPSTREAM kills the turn with zero retries. Non-5xx\n // transient/request errors (404, generic 400, other 4xx) stay terminal.\n if (classified.status !== undefined && classified.status >= 500) {\n throw new LlmError(\n `agy upstream error (${response.status}): ${classified.message ?? ''}`,\n SERVER_ERROR_CODE,\n {\n providerRetryAfterMs: classified.retryAfterMs ?? undefined,\n requestId: ProviderRequestId(generateAntigravityRequestId()),\n },\n )\n }\n throw new LlmError(\n `agy upstream error (${response.status}): ${classified.message ?? ''}`,\n UPSTREAM_ERROR_CODE,\n )\n }\n\n if (!response.body) {\n throw new LlmError('agy stream returned no body', UPSTREAM_ERROR_CODE)\n }\n\n try {\n yield* parseAgySse(response.body, {\n signal: options.signal,\n onToolSignature: (toolCallId, signature) => {\n setThoughtSignature(toolCallId, signature)\n },\n })\n await this.options.markSuccess?.(session)\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw new LlmError('agy stream aborted', 'ABORTED', { cause: error })\n }\n await this.options.reportFailure('network-error', session)\n throw new LlmError(\n error instanceof Error ? error.message : 'agy stream parse failed',\n UPSTREAM_ERROR_CODE,\n { cause: error },\n )\n }\n }\n}\n\nexport type { ToolSchema }\n","/**\n * Shared runtime construction for the in-harness plugin entries: master-key\n * codec resolution (credentials seam first, credentials document fallback),\n * account store, session manager, and adapter. Used by the main plugin\n * (adapter registration) and the web plugin (route registration) so both\n * entries operate on the same store.\n */\n\nimport { randomBytes } from 'node:crypto'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { AgyAdapter } from './adapter/adapter.ts'\nimport type { AgyAttachmentStore } from './adapter/adapter.ts'\nimport { AGY_PROVIDER } from './adapter/models.ts'\nimport { resolveAntigravityVersion } from './runtime/version.ts'\nimport { AgySessionManager } from './session.ts'\nimport { JsonAccountStore } from './store/accounts.ts'\nimport type { AccountStore } from './store/accounts.ts'\nimport {\n MASTER_KEY_REF,\n createAesGcmCodec,\n deriveKey,\n loadMasterKey,\n persistMasterKey,\n resolveDshHome,\n resolveMasterKeyCodec,\n} from './store/keyring.ts'\nimport type { SecretCodec } from './store/keyring.ts'\n\nexport interface CredentialsSeam {\n resolve(ref: string): Promise<{ value: string } | undefined>\n set(ref: string, value: string): Promise<void>\n}\n\nfunction codecFrom(masterKey: string): SecretCodec {\n return createAesGcmCodec(deriveKey(masterKey))\n}\n\n/** Resolve or create the master key, preferring the credentials seam when available. */\nexport async function resolveCodec(ctx: Context): Promise<{ codec: SecretCodec; created: boolean }> {\n const dshHome = resolveDshHome()\n const credentials = ctx.get('credentials') as CredentialsSeam | undefined\n\n if (credentials) {\n const resolved = await credentials.resolve(MASTER_KEY_REF)\n if (resolved) return { codec: codecFrom(resolved.value), created: false }\n const fileKey = loadMasterKey(dshHome)\n if (fileKey) return { codec: codecFrom(fileKey), created: false }\n const fresh = randomBytes(32).toString('hex')\n try {\n await credentials.set(MASTER_KEY_REF, fresh)\n return { codec: codecFrom(fresh), created: true }\n } catch {\n // Read-only shadowing: persist to the credentials document directly.\n persistMasterKey(dshHome, fresh)\n return { codec: codecFrom(fresh), created: true }\n }\n }\n\n return resolveMasterKeyCodec(dshHome)\n}\n\n/** Build the store, session manager, and adapter for one plugin entry. */\nexport async function createAgyRuntime(ctx: Context): Promise<{\n store: AccountStore\n sessions: AgySessionManager\n adapter: AgyAdapter\n}> {\n // Warm the version cache (non-blocking) so fingerprint generation inside\n // the rate-limit path never waits on a cold feed.\n void resolveAntigravityVersion().catch(() => {})\n const { codec } = await resolveCodec(ctx)\n const dshHome = resolveDshHome()\n const store = new JsonAccountStore({ file: `${dshHome}/agy-accounts.json`, codec })\n const sessions = new AgySessionManager({ store })\n // Optional background health probe (DSH_AGY_HEALTH_INTERVAL_MS), off by default.\n const healthIntervalMs = Number(process.env.DSH_AGY_HEALTH_INTERVAL_MS ?? 0)\n if (Number.isFinite(healthIntervalMs) && healthIntervalMs > 0) {\n sessions.startHealthProbe(healthIntervalMs)\n }\n const adapter = new AgyAdapter({\n getSession: (model) => sessions.getSession(model),\n reportFailure: (kind, session, info) => sessions.reportFailure(kind, session, info),\n markSuccess: (session) => sessions.markSuccess(session),\n resolveAttachments: () => ctx.get('attachments') as AgyAttachmentStore | undefined,\n })\n return { store, sessions, adapter }\n}\n\nexport { AGY_PROVIDER }\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { d as isAgyDisabled, f as generateFingerprint, g as resolveAntigravityVersionBounded, n as maskProxyUrl, p as recordFingerprintVersion } from "../accounts-Um8N9I56.mjs";
2
2
  import { a as proxyUrlForLogs, r as normalizeProxyUrl, t as isProxyReachable } from "../proxy-DQPIwUov.mjs";
3
- import { t as createAgyRuntime } from "../plugin-common-DHQVJtXd.mjs";
3
+ import { t as createAgyRuntime } from "../plugin-common-Di4n-1eR.mjs";
4
4
  import { t as exchangeAntigravity } from "../exchange-Bdql4kf3.mjs";
5
5
  import { n as upsertImportedAccount, r as authorizeAntigravity, t as importManySources } from "../import-BkqCMX7m.mjs";
6
6
  //#region src/web/i18n.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-agy",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "packageManager": "pnpm@11.10.0",
5
5
  "description": "Google Antigravity (agy) OAuth auth + model access plugin for DeepSeek Harness: multi-account pool, 429 rotation, device fingerprinting, CLI and web login.",
6
6
  "type": "module",
@@ -50,8 +50,8 @@
50
50
  "verify:blocks": "tsx scripts/verify-blocks.mts"
51
51
  },
52
52
  "peerDependencies": {
53
- "@deepseek-ai/cordis": "^4.0.1",
54
- "@deepseek-ai/dsh-llm": "^0.0.1-rc.1"
53
+ "@deepseek-ai/cordis": "^4.0.2",
54
+ "@deepseek-ai/dsh-llm": "^0.1.5-rc.1"
55
55
  },
56
56
  "peerDependenciesMeta": {
57
57
  "@deepseek-ai/cordis": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-common-DHQVJtXd.mjs","names":[],"sources":["../src/runtime/classify.ts","../src/adapter/adapter.ts","../src/plugin-common.ts"],"sourcesContent":["/**\n * Upstream failure classification: HTTP status + headers + body → FailureKind.\n * Conservative by design: only auth-failure may revoke an account; everything\n * else cools, rotates, or retries.\n */\n\nimport type { FailureKind } from '../types.ts'\nimport { isProxyUnreachableError } from '../proxy.ts'\n\nexport interface ClassifiedError {\n kind: FailureKind\n status?: number\n /** Server-provided retry delay (ms), when the response carried it. */\n retryAfterMs?: number\n /** Server-provided absolute reset time, when the response carried it. */\n resetTime?: string\n message?: string\n /** 429 sub-category, present when kind is rate-limit. */\n rateLimitCategory?: RateLimitCategory\n}\n\n/**\n * 429 sub-category (mirrors CLIProxyAPI/OmniRoute's classify429):\n * - soft_rate_limit: transient burst, retry immediately on the same account\n * - rate_limited: per-minute limit, short cooldown then retry (same account\n * when there is no other)\n * - quota_exhausted: daily/plan quota gone, long cooldown (24h)\n * - unknown: exponential backoff\n */\nexport type RateLimitCategory = 'soft_rate_limit' | 'rate_limited' | 'quota_exhausted' | 'unknown'\n\nconst QUOTA_EXHAUSTED_KEYWORDS = [\n 'quota_exhausted',\n 'quota exhausted',\n 'quota reached',\n 'enable overages',\n 'individual quota',\n]\n\n/** Classify a 429 body into the four upstream categories. */\nexport function classifyRateLimit(\n bodyText: string | undefined,\n retryAfterMs: number | undefined,\n): RateLimitCategory {\n const text = (bodyText ?? '').toLowerCase()\n if (QUOTA_EXHAUSTED_KEYWORDS.some((keyword) => text.includes(keyword))) {\n return 'quota_exhausted'\n }\n if (retryAfterMs !== undefined && retryAfterMs < 3000) {\n return 'soft_rate_limit'\n }\n if (retryAfterMs !== undefined) {\n return 'rate_limited'\n }\n // No explicit retry hint: \"quota\" wording → daily quota, otherwise unknown.\n return text.includes('quota') || text.includes('resource_exhausted') ? 'quota_exhausted' : 'unknown'\n}\n\nconst RATE_LIMIT_RESET_FIELDS = ['resetTime', 'reset_time', 'resetAt', 'quotaResetTime'] as const\n\nfunction extractResetTime(bodyText: string | undefined): string | undefined {\n if (!bodyText) return undefined\n try {\n const data = JSON.parse(bodyText) as Record<string, unknown>\n for (const field of RATE_LIMIT_RESET_FIELDS) {\n const value = data[field]\n if (typeof value === 'string' && value) return value\n if (typeof value === 'number' && Number.isFinite(value)) {\n // Unix ms when large, seconds when small (relative to now).\n return value > 1_000_000_000_000 ? new Date(value).toISOString() : new Date(Date.now() + value * 1000).toISOString()\n }\n }\n const quotaInfo = data.quotaInfo as Record<string, unknown> | undefined\n if (quotaInfo && typeof quotaInfo.resetTime === 'string') return quotaInfo.resetTime\n } catch {\n // not JSON — no reset info\n }\n return undefined\n}\n\nfunction parseRetryAfter(header: string | null): number | undefined {\n if (!header) return undefined\n const seconds = Number(header)\n if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000\n const date = Date.parse(header)\n if (!Number.isNaN(date)) return Math.max(0, date - Date.now())\n return undefined\n}\n\n/** Classify a completed HTTP response (non-2xx). */\nexport function classifyHttpError(\n status: number,\n headers: Headers,\n bodyText?: string,\n): ClassifiedError {\n const retryAfterMs = parseRetryAfter(headers.get('retry-after'))\n const resetTime = extractResetTime(bodyText)\n\n if (status === 429) {\n const category = classifyRateLimit(bodyText, retryAfterMs)\n return {\n kind: 'rate-limit',\n rateLimitCategory: category,\n status,\n retryAfterMs,\n resetTime,\n message: bodyText ? bodyText.slice(0, 200) : undefined,\n }\n }\n if (status === 401) {\n return { kind: 'auth-failure', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n if (status === 403) {\n // Google also reports quota walls as 403 RESOURCE_EXHAUSTED, and the\n // endpoint fallback chain ends on hosts answering 403 for \"no license\"\n // (not bad auth). Only treat a 403 as auth-failure when the body carries\n // no quota wording — a false revoke permanently disables the account.\n const category = classifyRateLimit(bodyText, undefined)\n if (category === 'quota_exhausted') {\n return {\n kind: 'rate-limit',\n rateLimitCategory: category,\n status,\n message: bodyText ? bodyText.slice(0, 200) : undefined,\n }\n }\n return { kind: 'auth-failure', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n if (status === 404) {\n // Model/route missing — nothing to rotate for; surface as transient request error.\n return { kind: 'transient', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n if (status >= 500) {\n return { kind: 'transient', status, retryAfterMs, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n if (status === 400) {\n // A 400 is a request-construction error (permanent — retrying sends the\n // same broken payload). Only capacity-style phrases are recoverable\n // (context overflow / model unavailable), mirroring OmniRoute's\n // classifyProviderError: everything else surfaces as a terminal\n // request-error so rotation does not waste attempts.\n const text = (bodyText ?? '').toLowerCase()\n const recoverable = (\n (text.includes('context') && (text.includes('overflow') || text.includes('too long') || text.includes('exceeded')))\n || (text.includes('model') && (text.includes('not found') || text.includes('unavailable') || text.includes('not supported')))\n )\n if (recoverable) {\n return { kind: 'transient', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n return { kind: 'request-error', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n }\n // 400-range others (401 handled above): request-level errors, no rotation semantics.\n return { kind: 'transient', status, message: bodyText ? bodyText.slice(0, 200) : undefined }\n}\n\n/** Classify a fetch-level failure (DNS, refused, timeout, abort). */\nexport function classifyFetchError(error: unknown): ClassifiedError {\n const message = error instanceof Error ? error.message : String(error)\n if (error instanceof DOMException && error.name === 'AbortError') {\n return { kind: 'network-error', message }\n }\n if (isProxyUnreachableError(error)) {\n return { kind: 'proxy-unreachable', message }\n }\n return { kind: 'network-error', message }\n}\n\n/** Classify the result of a refresh attempt (shared by adapter + verify paths). */\nexport function classifyRefreshFailure(status: number, code?: string): ClassifiedError {\n if (code === 'invalid_grant') return { kind: 'auth-failure', status, message: code }\n if (status === 429) return { kind: 'rate-limit', status, message: code }\n if (status >= 500) return { kind: 'transient', status, message: code }\n return { kind: 'transient', status, message: code }\n}\n\nexport type { FailureKind }\n","/**\n * AgyAdapter: the DSH seam. A thin orchestrator over the deep modules —\n * account session resolution (shell-provided), request translation, SSE\n * parsing, failure classification, and rotation reporting. All wire details\n * live in translate.ts / parse.ts / models.ts.\n */\n\nimport {\n LlmAdapter,\n LlmError,\n ProviderRequestId,\n QUOTA_EXCEEDED_CODE,\n attributionHeaders,\n} from '@deepseek-ai/dsh-llm'\nimport type {\n GenerateOptions,\n LlmModelInfo,\n LlmProviderInfo,\n LlmResolvedModelInfo,\n StreamChunk,\n ToolSchema,\n} from '@deepseek-ai/dsh-llm'\n\nexport interface PreparedAdapterCall {\n model: LlmResolvedModelInfo\n stream: (options: GenerateOptions) => AsyncIterable<StreamChunk>\n}\nimport { AgyAuthError, AgyPoolBlockedError } from '../types.ts'\nimport type { AgyAccountSession, FailureKind, ManagedAccount, OAuthAuthDetails } from '../types.ts'\nimport type { RateLimitCategory } from '../runtime/classify.ts'\nimport { fetchAgyFirstOk } from '../oauth/constants.ts'\nimport { classifyFetchError, classifyHttpError } from '../runtime/classify.ts'\nimport { deriveAntigravitySessionId, generateAntigravityRequestId } from '../runtime/identity.ts'\nimport { setThoughtSignature } from '../runtime/signature-cache.ts'\nimport { toAgyRequestBody } from './translate.ts'\nimport type { AgyResolvedImage } from './translate.ts'\nimport { resolveMultimodalFiles } from './multimodal.ts'\nimport { parseAgySse } from './parse.ts'\nimport { AGY_PROVIDER, catalogModelList, listAgyModels, resolveAgyModel } from './models.ts'\n\nexport type { AgyAccountSession }\n\n/**\n * Structural view of the harness attachment service (ctx.attachments).\n * Deliberately not an import of @deepseek-ai/dsh-attachment: the CLI bundle\n * must stay free of harness runtime dependencies, and the real store\n * satisfies this shape.\n */\nexport interface AgyAttachmentStore {\n readImage(ref: {\n attachmentId: string\n mediaType: string\n }): Promise<{ ref: { mediaType: string }; data: Uint8Array }>\n}\n\n/** Collect image refs from user-message content only (spec scope: user images; tool-result nesting out of scope). */\nfunction collectImageRefs(options: GenerateOptions): Array<{ attachmentId: string; mediaType: string }> {\n const refs: Array<{ attachmentId: string; mediaType: string }> = []\n for (const message of options.messages) {\n if (message.role !== 'user') continue\n for (const block of message.content) {\n if (block.type === 'image') refs.push(block.attachment)\n }\n }\n return refs\n}\n\nexport interface AgyAdapterOptions {\n /** Resolve the active account for a request (model-aware: family-scoped quota ranking). */\n getSession(model?: string): Promise<AgyAccountSession | undefined>\n /** Report a classified upstream failure so the shell can cool/rotate/revoke. */\n reportFailure(\n kind: FailureKind,\n session: AgyAccountSession,\n info?: {\n retryAfterMs?: number\n status?: number\n rateLimitCategory?: RateLimitCategory\n /** Server-reported absolute reset time; drives precise cooldowns. */\n resetTime?: string\n /** Requested model id; drives family-scoped rate-limit bookkeeping. */\n model?: string\n },\n ): Promise<void>\n /** Report a clean stream completion (resets the failure counter). */\n markSuccess?(session: AgyAccountSession): Promise<void>\n /** Resolve the harness attachment store; undefined outside the harness (standalone CLI). */\n resolveAttachments?(): AgyAttachmentStore | undefined\n}\n\nconst UPSTREAM_ERROR_CODE = 'UPSTREAM'\n/** First-class DSH retryable code: the default retry policy honors SERVER (5xx), not UPSTREAM. */\nconst SERVER_ERROR_CODE = 'SERVER'\n\n/** Build the impersonation headers for one request (per-request randomization applied by the shell). */\nexport function buildRequestHeaders(session: AgyAccountSession): Record<string, string> {\n return {\n authorization: `Bearer ${session.auth.access}`,\n 'content-type': 'application/json',\n accept: 'text/event-stream',\n 'x-goog-request-id': generateAntigravityRequestId(),\n ...attributionHeaders(),\n ...session.impersonation,\n }\n}\n\nexport class AgyAdapter extends LlmAdapter {\n private readonly options: AgyAdapterOptions\n\n constructor(options: AgyAdapterOptions) {\n super()\n this.options = options\n }\n\n override providerInfo(_provider: string): LlmProviderInfo {\n return { id: AGY_PROVIDER, name: 'Antigravity (agy)' }\n }\n\n override async listModels(_provider: string): Promise<readonly LlmModelInfo[]> {\n try {\n const session = await this.options.getSession()\n return await listAgyModels(session?.auth.access, session?.account.projectId)\n } catch (error) {\n if (error instanceof AgyPoolBlockedError || error instanceof AgyAuthError) {\n return catalogModelList()\n }\n throw error\n }\n }\n\n override async resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo> {\n return resolveAgyModel(provider, model)\n }\n\n // ponytail: DSH 0.1.1-rc.2+ calls prepareCall instead of stream directly — keep compatible with old base without override\n async prepareCall(provider: string, model: string, _signal?: AbortSignal): Promise<PreparedAdapterCall> {\n return {\n model: await this.resolveModel(provider, model),\n stream: (options: GenerateOptions) => this.stream(options),\n }\n }\n\n /**\n * Pre-resolve every image attachment into base64 bytes before translation.\n * Image input hard-fails with UNSUPPORTED_CONTENT (terminal, never retried)\n * when the store is missing or a read fails — silently dropping images and\n * sending text-only is the exact failure mode this path exists to prevent.\n */\n private async resolveRequestImages(options: GenerateOptions): Promise<Map<string, AgyResolvedImage>> {\n const refs = collectImageRefs(options)\n const images = new Map<string, AgyResolvedImage>()\n if (refs.length === 0) return images\n const store = this.options.resolveAttachments?.()\n if (!store) {\n throw new LlmError(\n 'agy image input requires the durable attachment service (in-harness plugin only)',\n 'UNSUPPORTED_CONTENT',\n )\n }\n // Read every attachment concurrently (N images cost one round-trip, not N).\n // allSettled rather than all: more than one read may reject, and the\n // surfaced error must be deterministic (first failure in ref order) instead\n // of whichever concurrent read happened to reject first — and no rejection\n // may escape as unhandled.\n const settled = await Promise.allSettled(\n refs.map(async (ref) => {\n const stored = await store.readImage(ref)\n return {\n attachmentId: ref.attachmentId,\n image: {\n mediaType: stored.ref.mediaType,\n data: Buffer.from(stored.data).toString('base64'),\n },\n }\n }),\n )\n const failedIndex = settled.findIndex((outcome) => outcome.status === 'rejected')\n if (failedIndex !== -1) {\n const ref = refs[failedIndex]!\n const cause: unknown = (settled[failedIndex] as PromiseRejectedResult).reason\n throw new LlmError(\n `agy image attachment \"${ref.attachmentId}\" could not be loaded: ${cause instanceof Error ? cause.message : String(cause)}`,\n 'UNSUPPORTED_CONTENT',\n { cause: cause instanceof Error ? cause : undefined },\n )\n }\n for (const outcome of settled) {\n if (outcome.status === 'fulfilled') {\n images.set(outcome.value.attachmentId, outcome.value.image)\n }\n }\n return images\n }\n\n override async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {\n // Spec D1 sequence: resolve images first — a locally-failing image request\n // must surface UNSUPPORTED_CONTENT (user story 8) instead of being masked\n // by account-pool errors, and must not touch pool state at all.\n const images = await this.resolveRequestImages(options)\n let session: AgyAccountSession | undefined\n try {\n session = await this.options.getSession(options.model)\n } catch (error) {\n if (error instanceof AgyAuthError) {\n if (error.kind === 'transport') {\n throw new LlmError(error.message, 'TRANSPORT', { cause: error })\n }\n if (error.kind === 'rate-limit') {\n throw new LlmError(error.message, 'RATE_LIMIT', {\n requestId: ProviderRequestId(generateAntigravityRequestId()),\n })\n }\n throw new LlmError(error.message, 'INVALID_CREDENTIAL', { cause: error })\n }\n if (error instanceof AgyPoolBlockedError) {\n if (error.kind === 'quota-exhausted') {\n throw new LlmError(error.message, QUOTA_EXCEEDED_CODE)\n }\n const delta = Math.ceil(error.blockedUntil - Date.now())\n const providerRetryAfterMs = Number.isFinite(delta) && delta > 0 ? delta : 1\n throw new LlmError(error.message, 'RATE_LIMIT', {\n providerRetryAfterMs,\n requestId: ProviderRequestId(generateAntigravityRequestId()),\n })\n }\n throw error\n }\n if (!session) {\n throw new LlmError(\n 'No agy account configured — run `dsh-agy login` to authenticate.',\n 'NO_CREDENTIAL',\n )\n }\n\n const multimodalFiles = await resolveMultimodalFiles(options)\n const body = toAgyRequestBody(options, {\n projectId: session.account.projectId,\n sessionId: deriveAntigravitySessionId(session.account.email) ?? undefined,\n ...(images.size > 0 ? { images } : {}),\n ...(multimodalFiles.size > 0 ? { multimodalFiles } : {}),\n })\n const headers = buildRequestHeaders(session)\n\n let response: Response\n try {\n response = await fetchAgyFirstOk('/v1internal:streamGenerateContent?alt=sse', {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: options.signal,\n })\n } catch (error) {\n const classified = classifyFetchError(error)\n await this.options.reportFailure(classified.kind, session)\n throw new LlmError(classified.message ?? 'agy fetch failed', 'TRANSPORT', { cause: error })\n }\n\n if (!response.ok) {\n const bodyText = await response.text().catch(() => undefined)\n const classified = classifyHttpError(response.status, response.headers, bodyText)\n await this.options.reportFailure(classified.kind, session, {\n retryAfterMs: classified.retryAfterMs,\n status: response.status,\n rateLimitCategory: classified.rateLimitCategory,\n resetTime: classified.resetTime,\n model: options.model,\n })\n if (classified.kind === 'rate-limit') {\n // soft/rate limits are retryable by the harness (RATE_LIMIT + delay);\n // daily quota exhaustion is terminal (QUOTA, 24h cooldown already set).\n if (classified.rateLimitCategory === 'quota_exhausted') {\n throw new LlmError(\n `agy daily quota exhausted (${response.status}): ${classified.message ?? ''}`,\n QUOTA_EXCEEDED_CODE,\n )\n }\n throw new LlmError(\n `agy rate-limited (${response.status}): ${classified.message ?? ''}`,\n 'RATE_LIMIT',\n {\n providerRetryAfterMs: classified.retryAfterMs ?? undefined,\n requestId: ProviderRequestId(generateAntigravityRequestId()),\n },\n )\n }\n if (classified.kind === 'auth-failure') {\n throw new LlmError(\n `agy authentication failed (${response.status}) — run \\`dsh-agy login\\``,\n 'INVALID_CREDENTIAL',\n )\n }\n // 5xx upstream failures (e.g. 503 \"No capacity available\") are transient:\n // the DSH retry policy honors SERVER but treats UPSTREAM as terminal, so\n // classifying 5xx as UPSTREAM kills the turn with zero retries. Non-5xx\n // transient/request errors (404, generic 400, other 4xx) stay terminal.\n if (classified.status !== undefined && classified.status >= 500) {\n throw new LlmError(\n `agy upstream error (${response.status}): ${classified.message ?? ''}`,\n SERVER_ERROR_CODE,\n {\n providerRetryAfterMs: classified.retryAfterMs ?? undefined,\n requestId: ProviderRequestId(generateAntigravityRequestId()),\n },\n )\n }\n throw new LlmError(\n `agy upstream error (${response.status}): ${classified.message ?? ''}`,\n UPSTREAM_ERROR_CODE,\n )\n }\n\n if (!response.body) {\n throw new LlmError('agy stream returned no body', UPSTREAM_ERROR_CODE)\n }\n\n try {\n yield* parseAgySse(response.body, {\n signal: options.signal,\n onToolSignature: (toolCallId, signature) => {\n setThoughtSignature(toolCallId, signature)\n },\n })\n await this.options.markSuccess?.(session)\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw new LlmError('agy stream aborted', 'ABORTED', { cause: error })\n }\n await this.options.reportFailure('network-error', session)\n throw new LlmError(\n error instanceof Error ? error.message : 'agy stream parse failed',\n UPSTREAM_ERROR_CODE,\n { cause: error },\n )\n }\n }\n}\n\nexport type { ToolSchema }\n","/**\n * Shared runtime construction for the in-harness plugin entries: master-key\n * codec resolution (credentials seam first, credentials document fallback),\n * account store, session manager, and adapter. Used by the main plugin\n * (adapter registration) and the web plugin (route registration) so both\n * entries operate on the same store.\n */\n\nimport { randomBytes } from 'node:crypto'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { AgyAdapter } from './adapter/adapter.ts'\nimport type { AgyAttachmentStore } from './adapter/adapter.ts'\nimport { AGY_PROVIDER } from './adapter/models.ts'\nimport { resolveAntigravityVersion } from './runtime/version.ts'\nimport { AgySessionManager } from './session.ts'\nimport { JsonAccountStore } from './store/accounts.ts'\nimport type { AccountStore } from './store/accounts.ts'\nimport {\n MASTER_KEY_REF,\n createAesGcmCodec,\n deriveKey,\n loadMasterKey,\n persistMasterKey,\n resolveDshHome,\n resolveMasterKeyCodec,\n} from './store/keyring.ts'\nimport type { SecretCodec } from './store/keyring.ts'\n\nexport interface CredentialsSeam {\n resolve(ref: string): Promise<{ value: string } | undefined>\n set(ref: string, value: string): Promise<void>\n}\n\nfunction codecFrom(masterKey: string): SecretCodec {\n return createAesGcmCodec(deriveKey(masterKey))\n}\n\n/** Resolve or create the master key, preferring the credentials seam when available. */\nexport async function resolveCodec(ctx: Context): Promise<{ codec: SecretCodec; created: boolean }> {\n const dshHome = resolveDshHome()\n const credentials = ctx.get('credentials') as CredentialsSeam | undefined\n\n if (credentials) {\n const resolved = await credentials.resolve(MASTER_KEY_REF)\n if (resolved) return { codec: codecFrom(resolved.value), created: false }\n const fileKey = loadMasterKey(dshHome)\n if (fileKey) return { codec: codecFrom(fileKey), created: false }\n const fresh = randomBytes(32).toString('hex')\n try {\n await credentials.set(MASTER_KEY_REF, fresh)\n return { codec: codecFrom(fresh), created: true }\n } catch {\n // Read-only shadowing: persist to the credentials document directly.\n persistMasterKey(dshHome, fresh)\n return { codec: codecFrom(fresh), created: true }\n }\n }\n\n return resolveMasterKeyCodec(dshHome)\n}\n\n/** Build the store, session manager, and adapter for one plugin entry. */\nexport async function createAgyRuntime(ctx: Context): Promise<{\n store: AccountStore\n sessions: AgySessionManager\n adapter: AgyAdapter\n}> {\n // Warm the version cache (non-blocking) so fingerprint generation inside\n // the rate-limit path never waits on a cold feed.\n void resolveAntigravityVersion().catch(() => {})\n const { codec } = await resolveCodec(ctx)\n const dshHome = resolveDshHome()\n const store = new JsonAccountStore({ file: `${dshHome}/agy-accounts.json`, codec })\n const sessions = new AgySessionManager({ store })\n // Optional background health probe (DSH_AGY_HEALTH_INTERVAL_MS), off by default.\n const healthIntervalMs = Number(process.env.DSH_AGY_HEALTH_INTERVAL_MS ?? 0)\n if (Number.isFinite(healthIntervalMs) && healthIntervalMs > 0) {\n sessions.startHealthProbe(healthIntervalMs)\n }\n const adapter = new AgyAdapter({\n getSession: (model) => sessions.getSession(model),\n reportFailure: (kind, session, info) => sessions.reportFailure(kind, session, info),\n markSuccess: (session) => sessions.markSuccess(session),\n resolveAttachments: () => ctx.get('attachments') as AgyAttachmentStore | undefined,\n })\n return { store, sessions, adapter }\n}\n\nexport { AGY_PROVIDER }\n"],"mappings":"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"}