Skip to content

WING-193 cloud study-guide provider vertical

POST /api/cloud/study-guide is the first provider-backed feature path designed for the shared desktop, YC, and Flow API surface. It accepts a topic, learning goals, source material, and an explicit consentToCloudProcessing acknowledgement. Desktop uses the per-launch trusted-app token. The server edition requires a valid tenant session plus its session-bound CSRF token; there is no shared browser API-key fallback.

The service only resolves an explicitly configured ILlmHarnessMeta.Kind == "key" provider. It never falls back to a desktop CLI, local Ollama, or the user's default provider. Missing or invalid provider/pricing configuration returns NotConfigured without sending content.

Configuration

Supply these as runtime configuration or Secret Manager-backed environment values:

WorkWingman__CloudProviders__StudyGuide__ProviderId=openai
WorkWingman__CloudProviders__StudyGuide__MaximumInputTokens=5000
WorkWingman__CloudProviders__StudyGuide__MaximumOutputTokens=4096
WorkWingman__CloudProviders__StudyGuide__InputUsdPerMillionTokens=<current operator-verified price>
WorkWingman__CloudProviders__StudyGuide__OutputUsdPerMillionTokens=<current operator-verified price>
WorkWingman__CloudProviders__StudyGuide__MaximumEstimatedCostUsd=0.10
WorkWingman__CloudProviders__StudyGuide__MaximumDailySpendUsd=1.00
WorkWingman__CloudProviders__StudyGuide__MaximumAttempts=2

The API key itself uses the existing vault/config key provider and must be injected separately. For server edition, map exactly one Secret Manager secret to the configuration key that matches ProviderId: WorkWingman__OpenAiApiKey for openai, or WorkWingman__AnthropicApiKey for anthropic. Missing/mismatched secrets leave the feature locked; there is no CLI, local-model, or process-wide browser-key fallback. Never put a key or a real price assumption in source. MaximumDailySpendUsd is stored as integer micro-USD and must be either zero (feature disabled) or at least 0.000001; a smaller positive value fails startup. MaximumOutputTokens must remain 4096, matching the hard max_tokens value enforced by the real OpenAI and Anthropic adapters; this keeps the displayed worst-case estimate from understating the billable ceiling.

Safety and accounting

  • Consent, trusted-caller authentication, input size, token estimate, cost ceiling, provider configuration, and provider availability are checked before content leaves the process.
  • The route admits three calls per authenticated tenant per minute. Before generation, an atomic durable counter reserves the configured worst-case cost (including every allowed retry) against that tenant's UTC-day ceiling. A refused reservation returns TenantSpendLimitExceeded without a provider call. Separate tenants have separate counters.
  • Input tokens use a conservative deterministic one-token-per-UTF-8-byte estimate for the preflight, avoiding underestimates for code, emoji, CJK, or adversarial input. The response labels the resulting amount as an estimate.
  • Actual provider-reported token counts flow through MeteringLlmHarness into the content-free AI usage ledger. Prompts, source material, provider keys, and generated text are never logged.
  • The orchestration layer retries at most three times, and only when a provider explicitly marks a failure transient and retry-safe. The current paid generation adapters report ambiguous failures as final to avoid accidental double billing.
  • Caller cancellation propagates. Unconfigured, unavailable, over-limit, and provider-failure outcomes fail closed with no deterministic local imitation presented as cloud output.

The provider vertical is an authenticated, CSRF-protected tenant route admitted in the first private server pilot. Prompt and result content are not persisted; only the content-free daily spend reservation counter is durable. Every legacy data route remains locked until its repositories are tenant-isolated end to end.