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
TenantSpendLimitExceededwithout 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
MeteringLlmHarnessinto 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.