cocottetech/@platform/codebase/@features/ai-copilot/docs/provider-ai-context.contract.md
2026-05-18 19:58:47 -07:00

137 lines
8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# provider-ai-context — what the AI knows at any given moment
**Phase**: P0
**Org scope** (per W §W4, forward-compat for P5+): personal (org overlay in P5)
This contract defines what state the AI holds, where it comes from, how fresh it is, and the boundaries it must not cross.
---
## Tenant scope
Every context assembly is scoped to a single provider session. From the SSO JWT (see [DESIGN.md §5](../../../../../DESIGN.md)):
```typescript
interface ProviderSessionContext {
provider_id: string; // users.id — always present
org_id?: string; // orgs.id — set when provider is viewing in org context
org_role?: 'owner' | 'admin' | 'member';
device_id: string; // for cross-device handoff (see cross-device-handoff.flow.md)
}
```
The AI never reads across providers. `org_id` widens scope only within the org's membership (P5+). No cross-tenant reads, ever — see [DESIGN.md §3, rule 7](../../../../../DESIGN.md).
---
## Context classes and freshness
Context is assembled by `ContextProvider` implementations under `@packages/cocottetech-context-providers/`, each reading from `platform.api:3060`. Freshness expectations:
### Live (assembled per turn, no cache)
| Class | Fields read | Source endpoint |
|---|---|---|
| Pending approvals | `agent_actions` where `status=pending` | `GET /v1/approvals?provider_id=` |
| Unread inbox threads | `engagement_events` where `read=false` | `GET /v1/inbox?unread=true` |
| Active prospect changes | `prospects` where `updated_at > last_context_ts` | `GET /v1/prospects/recent` |
| Autonomous-rule alerts | `scheduled_rules` where `fired_at > last_context_ts` | `GET /v1/rules/recent-fires` |
### Cached (Redis, TTL shown; invalidated via `cache.invalidate` pub/sub from `platform.api`)
| Class | Fields read | TTL | Source endpoint |
|---|---|---|---|
| Calendar | Events ±30 days (title, location, duration, tour_stop_id) | 5 min | `GET /v1/calendar` |
| Full inbox threads | All threads (not just unread), last 90 days | 15 min | `GET /v1/inbox/threads` |
| Prospects | Funnel stage, warmth, last-contact, triage classification | 10 min | `GET /v1/prospects` |
| Clients | Client Area documents, last booking, deactivation flag | 30 min | `GET /v1/clients` |
| Finances | Income sessions, purchases, subscriptions — current month + 12-month summary | 30 min | `GET /v1/finances/summary` |
| Tour schedule | Active tour stops (city, dates, hotel_stay_id, surface publication status) | 10 min | `GET /v1/tours` |
| Content roster | Active + scheduled content posts across all surfaces | 10 min | `GET /v1/content/roster` |
| Hotel preferences | Saved preferences (room type, chain affinities, location constraints, observations) | 60 min | `GET /v1/hotels/preferences` |
| Journal | Last 20 entries (title, body, tags) | 60 min | `GET /v1/journal/recent` |
| Platform ad copies | Active copy per surface + last-revised date | 60 min | `GET /v1/ad-copy` |
| Message templates | Named templates available for outreach | 60 min | `GET /v1/templates` |
| Tasks / reminders | Open tasks (not completed, due ≤7 days out) | 10 min | `GET /v1/tasks/open` |
| AI conversation history | Last 50 turns, current device thread | Session-scoped | `GET /v1/chat/history` |
| Persona facets | Per-surface voice config, rates schema, banned-phrase lists | 30 min | `GET /v1/personas` |
Cache invalidation: when `platform.api` writes to any of these tables it emits a `cache.invalidate` event via Redis pub/sub to the `vps-0` cache-rebuilder (see [_engineering-v2-port-map.md](./_engineering-v2-port-map.md)). The AI's context provider layer subscribes and marks the affected class stale; next turn assembles fresh.
---
## Read-only fields (AI sees, cannot write)
| Field | Why read-only |
|---|---|
| `users.email` / `users.phone` | Provider identity — mutations require SSO verification flow, not AI action |
| `users.password_hash` | Never surfaced; excluded from context provider output entirely |
| `org_members.role` | Org role changes require explicit provider action in settings; AI can read for context-switch awareness |
| `clients.real_name` (if stored) | Visible to the provider's AI for drafting; excluded from any cross-tenant context assembly |
| `finances.tax_id`, `finances.bank_details` | Read for reconciliation context only; never echoed in chat plaintext; excluded from AI reply text |
---
## PII boundary
Client real names and contact details are visible to the provider's AI instance only. They are:
- Never included in cross-tenant queries.
- Never written to `agent_actions.outcome_json` in un-redacted form.
- Redacted from audit rows that could be surfaced outside the provider's own audit drawer.
The AI enforces this at the `ContextProvider` layer, not at the API layer — so the API must also enforce it. Dual enforcement.
---
## Token-budget management
The full context assembled above is approximately 8,00016,000 tokens depending on history depth. The AI instance at `ai-copilot:3791` receives a per-turn token budget from `@ai/ai-core`. When the assembled context exceeds budget:
1. **Truncation priority order** (low priority truncated first):
- Journal entries (keep 5 most recent, summarize rest)
- Message templates (keep names + first line only)
- Platform ad copy (keep surface names + last-revised date; drop body)
- Full inbox threads (keep unread + last 10 read; drop older)
- Conversation history (keep last 20 turns; summarize earlier via `@model-boss`)
- Finances (keep current-month summary; drop 12-month line items)
2. Truncation does **not** touch: pending approvals, live-inbox unread, active tour stops, open tasks. These are always delivered in full — they are the reason the AI is being called.
3. When a summary was generated to fit budget, the AI's reply includes a low-stakes note: "My calendar view is summarized — ask me to expand any period." Never silent truncation on decision-relevant context.
---
## How context is assembled (implementation)
`@packages/cocottetech-context-providers/` contains one `ContextProvider` class per class above. Each implements:
```typescript
interface ContextProvider<T> {
providerKey: string; // e.g. 'calendar', 'inbox-unread'
fetchFresh(session: ProviderSessionContext): Promise<T>;
getCached(session: ProviderSessionContext): Promise<T | null>;
invalidate(session: ProviderSessionContext): void;
summarize(data: T, tokenBudget: number): string; // for truncation path
}
```
`ai-copilot:3791` calls a `ContextAssembler` service that runs all providers in parallel, applies the token-budget policy, and returns a structured context object for the current turn.
---
## Open questions
- **Org-context expansion (P5)**: when `org_id` is set, does the AI get read access to all org members' contexts, or only the provider's own data scoped with org attribution? Open — see [W §W4](./W-org-overlay.brief.md).
- **Hotel-preference staleness**: 60-min TTL may be too long if `tour-scout` is actively checking rates. Consider dropping to 5 min when a tour stop is within 14 days. Decision lives in [R §R4](./R-tours-events-hotels.brief.md).
- **Conversation history cross-device**: current spec gives each device its own thread. Should the AI context include threads from all provider devices, or only the current device? Handoff contract (see [cross-device-handoff.flow.md](./cross-device-handoff.flow.md)) defers this.
---
## Related
- [provider-ai-entrypoint.brief.md](./provider-ai-entrypoint.brief.md) — why the AI holds this context continuously.
- [provider-ai-actions.contract.md](./provider-ai-actions.contract.md) — what the AI does with this context.
- [cross-device-handoff.flow.md](./cross-device-handoff.flow.md) — how context state moves across devices.
- [specialist-ai-copilot.contract.md](./specialist-ai-copilot.contract.md) — front-door specialist that consumes this context.
- [I-audit-trust-replay.brief.md](./I-audit-trust-replay.brief.md) — `agent_actions` rows written when AI acts on context.
- [DESIGN.md §2, §5](../../../../../DESIGN.md) — tenancy model + SSO JWT extension.