toga-ai 1.0.973 → 1.0.974
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/CLAUDE.md +1 -1
- package/knowledge/1.0/apps/tools/features/talos-pricing-ui.md +8 -8
- package/knowledge/2.0/apps/_underscore/features/email-send-pipeline.md +2 -2
- package/knowledge/2.0/apps/api2/features/nested-relationship-writes.md +3 -3
- package/knowledge/2.0/apps/toga-blox/features/talos-assistant.md +5 -5
- package/knowledge/2.0/apps/toga-blox/workflows/local-link-into-a-consumer-app.md +3 -3
- package/knowledge/2.0/apps/toga25-supply/INDEX.md +1 -1
- package/knowledge/2.0/apps/toga25-supply/features/talos-integration.md +40 -142
- package/knowledge/2.0/apps/worker2/INDEX.md +1 -0
- package/knowledge/2.0/apps/worker2/features/callback-scheduling.md +8 -8
- package/knowledge/2.0/apps/worker2/features/clickup-task-fluffer-talos.md +2 -2
- package/knowledge/2.0/apps/worker2/features/talos-meeting-notes-integration.md +3 -3
- package/knowledge/2.0/apps/worker2/features/talos-pricing-automation.md +7 -7
- package/knowledge/2.0/apps/worker2/features/vapi-webhook-handler.md +11 -11
- package/knowledge/CONVENTIONS.md +3 -2
- package/knowledge/INDEX.md +6 -6
- package/knowledge/clients/compass-usa/INDEX.md +1 -0
- package/knowledge/clients/compass-usa/profile.md +7 -1
- package/knowledge/clients/nychh/INDEX.md +1 -1
- package/knowledge/clients/nychh/features/talos-assistant-enablement.md +40 -72
- package/knowledge/clients/nychh/profile.md +8 -2
- package/knowledge/clients/office-depot/INDEX.md +2 -2
- package/knowledge/clients/office-depot/features/odp-tech-support.md +46 -89
- package/knowledge/clients/office-depot/profile.md +13 -38
- package/knowledge/clients/tow-foundation/INDEX.md +1 -0
- package/knowledge/clients/tow-foundation/profile.md +9 -2
- package/knowledge/clients/true/INDEX.md +2 -0
- package/knowledge/clients/true/profile.md +12 -2
- package/knowledge/registry.json +21 -11
- package/knowledge/standalone/apps/claude/workflows/mcp-tool-usage.md +4 -4
- package/knowledge/standalone/apps/talos-backend/features/deep-agent-harness.md +3 -2
- package/knowledge/standalone/apps/talos-backend/features/tenant-configuration.md +3 -2
- package/package.json +1 -1
- package/knowledge/2.0/apps/ai-bdr/INDEX.md +0 -17
- package/knowledge/2.0/apps/ai-bdr/architecture.md +0 -154
- package/knowledge/2.0/apps/ai-bdr/features/bdr-web-funnel-plan.md +0 -282
- package/knowledge/2.0/apps/ai-bdr/features/call-orchestration.md +0 -207
- package/knowledge/2.0/apps/ai-bdr/features/campaign-chat-handoff.md +0 -115
- package/knowledge/2.0/apps/ai-bdr/features/landing-call-flow.md +0 -158
- package/knowledge/2.0/apps/ai-bdr/features/landing-chat-drawer.md +0 -124
- package/knowledge/2.0/apps/ai-bdr/features/live-call-status.md +0 -104
- package/knowledge/2.0/apps/ai-bdr/features/security-landing-page.md +0 -146
- package/knowledge/2.0/apps/ai-bdr/features/vapi-integration.md +0 -148
- package/knowledge/2.0/apps/ai-bdr/features/web-funnel-app.md +0 -305
- package/knowledge/2.0/apps/ai-bdr/features/web-funnel-content-model.md +0 -98
- package/knowledge/2.0/apps/ai-bdr/workflows/new-campaign-onboarding.md +0 -111
- package/knowledge/2.0/apps/ai-bdr/workflows/safe-call-loop-testing.md +0 -86
- package/knowledge/2.0/apps/talos/INDEX.md +0 -12
- package/knowledge/2.0/apps/talos/architecture.md +0 -140
- package/knowledge/2.0/apps/talos/features/aegra-api.md +0 -195
- package/knowledge/2.0/apps/talos/features/chat-frontend.md +0 -129
- package/knowledge/2.0/apps/talos/features/deployment.md +0 -94
- package/knowledge/2.0/apps/talos/features/mcp-servers.md +0 -109
- package/knowledge/2.0/apps/talos/features/observability.md +0 -107
- package/knowledge/2.0/apps/talos/features/pricing-cogs-model.md +0 -221
- package/knowledge/2.0/apps/talos/features/talos-agent.md +0 -167
- package/knowledge/2.0/apps/talos-backend/INDEX.md +0 -5
- package/knowledge/2.0/apps/talos-backend/workflows/toga-supply-client-onboarding.md +0 -210
- package/knowledge/2.0/apps/voice-to-voice/INDEX.md +0 -8
- package/knowledge/2.0/apps/voice-to-voice/architecture.md +0 -137
- package/knowledge/2.0/apps/voice-to-voice/features/livekit-pipeline.md +0 -120
- package/knowledge/2.0/apps/voice-to-voice/features/post-call-lambda.md +0 -146
- package/knowledge/2.0/apps/voice-to-voice/features/ticket-api-integration.md +0 -205
- package/knowledge/2.0/standards/python.md +0 -109
package/CLAUDE.md
CHANGED
|
@@ -25,9 +25,9 @@ related:
|
|
|
25
25
|
- ./persona-gated-navigation.md
|
|
26
26
|
- ./mvc-data-access-patterns.md
|
|
27
27
|
- ../architecture.md
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
28
|
+
- ../../../../standalone/apps/talos-backend/architecture.md
|
|
29
|
+
- ../../../../2.0/apps/worker2/features/talos-pricing-cogs-model.md
|
|
30
|
+
- ../../../../2.0/apps/worker2/features/talos-pricing-automation.md
|
|
31
31
|
---
|
|
32
32
|
|
|
33
33
|
The 1.0 (tools) face of the Talos Pricing Platform — Contracts / Pricing Dashboard / Usage / Pricing Settings pages + the estimate engine, reading the Team DB via `db_team`; open for the contract lifecycle, worker-owned read-only rows, or the fetchOne/PHP 8.5 traps.
|
|
@@ -43,7 +43,7 @@ The old Onboarding page could only **INSERT** (hardcoded `status='ONBOARDED'`, n
|
|
|
43
43
|
- **A signed contract can never be hard-deleted.** `TalosPricingBands` is `ON DELETE CASCADE`, so deleting the client would destroy the agreed rate schedule and the margin history with it. Signed contracts **churn**; they do not delete.
|
|
44
44
|
- **Post-signature edits append to `TalosContractAmendments`** rather than mutating the signed terms.
|
|
45
45
|
- Includes an **Actual-vs-Estimate** comparison with variance chips, a month-by-month history table plus cost/margin chart, and a one-click **"apply recommended org fee"**.
|
|
46
|
-
- **Pricing model toggle + contract terms (2026-09-17).** The page now sets `pricingModel` (`PER_USER` / `PER_INTERACTION`), the fixed 1/3/5-year term dropdown (`contractTermMonths`), the per-interaction inputs (`contractedInteractionCount`, voice-only `avgMinutesPerInteraction`, `perInteractionFee`), and the two one-time contract fees (`implementationFee`, `trainingFee`). Model design, term ramp, fee amortization, and the recurring-vs-blended margin split are all in [pricing-cogs-model](
|
|
46
|
+
- **Pricing model toggle + contract terms (2026-09-17).** The page now sets `pricingModel` (`PER_USER` / `PER_INTERACTION`), the fixed 1/3/5-year term dropdown (`contractTermMonths`), the per-interaction inputs (`contractedInteractionCount`, voice-only `avgMinutesPerInteraction`, `perInteractionFee`), and the two one-time contract fees (`implementationFee`, `trainingFee`). Model design, term ramp, fee amortization, and the recurring-vs-blended margin split are all in [pricing-cogs-model](../../../../2.0/apps/worker2/features/talos-pricing-cogs-model.md) — not restated here.
|
|
47
47
|
|
|
48
48
|
### Pricing Dashboard (`pricing/get.php`) — rebuilt for sales leadership
|
|
49
49
|
Portfolio KPIs, a 12-month blended-margin trend with the target band shaded, an exception list with deterministic explanations, and licensed-vs-active utilisation.
|
|
@@ -59,7 +59,7 @@ Technical-only (persona-narrowed on the action, per `mvc-data-access-patterns`).
|
|
|
59
59
|
- `mvc/talos/onboarding/*` and `mvc/talos/factors/*` — superseded above.
|
|
60
60
|
|
|
61
61
|
### Estimator (`App_Talos_Estimator`, `_/app/talos/estimator.php`)
|
|
62
|
-
Now driven by the **token unit price** and **workload profiles** instead of the feature checklist and per-client calibration factor (methodology in `pricing-cogs-model`). Service offering (CHAT / VOICE_TO_VOICE / NATURAL_VOICE) describes **modality only** and says nothing about cost; cost is driven by tool-call **intensity** via the profile (retrieval / general / analytics). Per-interaction model adds `costPerInteraction`, `estimateByInteraction`, `recommendedPricePerInteraction`, `recommendedOrgFeeInteraction`, `orgFeeOptionsInteraction`. Constants live in Team-DB `TalosCostFactors` (shared with worker2); a golden-master parity test (`estimator.parity.test.php` ↔ worker2 `PricingParityTest.php`, 11/11 pass) guards drift — see [pricing-cogs-model](
|
|
62
|
+
Now driven by the **token unit price** and **workload profiles** instead of the feature checklist and per-client calibration factor (methodology in `pricing-cogs-model`). Service offering (CHAT / VOICE_TO_VOICE / NATURAL_VOICE) describes **modality only** and says nothing about cost; cost is driven by tool-call **intensity** via the profile (retrieval / general / analytics). Per-interaction model adds `costPerInteraction`, `estimateByInteraction`, `recommendedPricePerInteraction`, `recommendedOrgFeeInteraction`, `orgFeeOptionsInteraction`. Constants live in Team-DB `TalosCostFactors` (shared with worker2); a golden-master parity test (`estimator.parity.test.php` ↔ worker2 `PricingParityTest.php`, 11/11 pass) guards drift — see [pricing-cogs-model](../../../../2.0/apps/worker2/features/talos-pricing-cogs-model.md).
|
|
63
63
|
|
|
64
64
|
## Gotchas
|
|
65
65
|
- **`App_Database::fetchOne()` is not an existence test** — it 500s on zero rows. See [mvc-data-access-patterns](./mvc-data-access-patterns.md); the original `onboarding/post.php` carried this exact bug and would have fataled on the first save anyone attempted, which is good evidence nobody ever completed an onboarding through it.
|
|
@@ -80,6 +80,6 @@ Now driven by the **token unit price** and **workload profiles** instead of the
|
|
|
80
80
|
- [Persona-gated navigation](./persona-gated-navigation.md)
|
|
81
81
|
- [Tools MVC — data-access patterns](./mvc-data-access-patterns.md)
|
|
82
82
|
- [Tools architecture](../architecture.md)
|
|
83
|
-
- [Talos architecture (
|
|
84
|
-
- [Pricing COGS model (
|
|
85
|
-
- [Talos pricing automation (worker2)](
|
|
83
|
+
- [Talos architecture (standalone)](../../../../standalone/apps/talos-backend/architecture.md)
|
|
84
|
+
- [Pricing COGS model (worker2)](../../../../2.0/apps/worker2/features/talos-pricing-cogs-model.md)
|
|
85
|
+
- [Talos pricing automation (worker2)](../../../../2.0/apps/worker2/features/talos-pricing-automation.md)
|
|
@@ -18,7 +18,7 @@ related:
|
|
|
18
18
|
- email-template-sending.md
|
|
19
19
|
- string-html-entity-helpers.md
|
|
20
20
|
- ../../worker2/features/all-client-email-queue-monitor.md
|
|
21
|
-
-
|
|
21
|
+
- ../../../../standalone/apps/bdr/features/web-funnel-app.md
|
|
22
22
|
- ../../../clients/compass-canada/features/french-order-email-localization.md
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -169,7 +169,7 @@ derive one from the other).
|
|
|
169
169
|
be paired with updating BDR's env, or BDR's Send button can only reach its *failed* state (it
|
|
170
170
|
has no mail-app fallback). Settings BDR mirrors: AWS SES **us-west-2**, port **587**, TLS;
|
|
171
171
|
`DevTeam@goagilant.com` is a known-good verified sender identity in worker2 config. See
|
|
172
|
-
[ai-bdr web-funnel-app.md](
|
|
172
|
+
[ai-bdr web-funnel-app.md](../../../../standalone/apps/bdr/features/web-funnel-app.md).
|
|
173
173
|
|
|
174
174
|
- **⚠ READ-AFTER-WRITE ON THE READER REPLICA LOSES `send()`'S OWN LOG ROW (deterministic).**
|
|
175
175
|
`_Email::send()` INSERTs the `PENDING` `Logs_[Client].Email` row, then reads `$emailLog->id`
|
|
@@ -22,7 +22,7 @@ related:
|
|
|
22
22
|
- ../../toga2-supply/features/currency-amount-lines-editor.md
|
|
23
23
|
- cxml-shipnotice-gateway.md
|
|
24
24
|
- ../../../clients/aig/features/entitlement-intake.md
|
|
25
|
-
-
|
|
25
|
+
- ../../../../standalone/apps/bdr/features/web-funnel-app.md
|
|
26
26
|
- ../../worker2/features/vapi-webhook-handler.md
|
|
27
27
|
- ../../../clients/elite/features/netsuite-togasupply-sync.md
|
|
28
28
|
- ../../dbchanges2/workflows/client-schema-drift-audit.md
|
|
@@ -52,7 +52,7 @@ Implemented in `Component/Api/V2/V2.php` (`getForeignKeyValue()` / the nested-wr
|
|
|
52
52
|
To **create** a new related record, send its data **without** an identifier (and accept that a new row is written). Never rely on a non-identifier field (a custom field, a name, an email) to de-duplicate — the engine will not use it to match, and you accumulate duplicate empty child rows on every write. If you need to link by a business key (like an employee XID), **resolve that key to a uuid in your caller first** (e.g. a `key → uuid` map), then send `{uuid}`.
|
|
53
53
|
|
|
54
54
|
**UPDATE-path back-reference injection defeats the uuid forced-MATCH (primary-pointer bug).** A **single-key identifier object** (`{uuid: <x>}` and nothing else) is supposed to hit the engine's **forced-MATCH fast-path** (`V2.php:6952`) — link the existing child, never create, and let the caller re-point a parent's forward FK to it. On the **CREATE** path this works: the set-loop (`V2.php:4601–4616`) applies the child object and the parent FK is assigned at `V2.php:4647` with no interference. On the **UPDATE** path it does **not**. When a child model carries a `contactId` FK *back* to the parent (as `ContactPhoneNumbers` → `Contacts` does), the update path **injects a reverse back-reference** (sets the child's `contactId = parent id`) into the nested child object at `V2.php:4985–4996` — added by commit `91d803f` "guard child FK set". That injection turns the single-key object into a **multi-key** object, so it no longer qualifies for forced-MATCH, and it diverts what `getForeignKeyValue()` returns **before** the parent's forward FK is assigned at `V2.php:5047`. Net effect: a `PUT {primaryContactPhoneNumber: {uuid}}` does **not** set `Contacts.primaryContactPhoneNumberId`, and the `PUT` response **echoes `primaryContactPhoneNumber: null`** on the miss.
|
|
55
|
-
- **Scope.** Any **forward singular FK** whose child model has a back-FK to the parent is exposed on update — `primaryContactEmailAddress` / `primaryContactAddress` on `Contacts` are likely affected the same way. Root cause of the **BDR web-funnel "phone-less contact is never dialed"** bug: see [web-funnel-app.md](
|
|
55
|
+
- **Scope.** Any **forward singular FK** whose child model has a back-FK to the parent is exposed on update — `primaryContactEmailAddress` / `primaryContactAddress` on `Contacts` are likely affected the same way. Root cause of the **BDR web-funnel "phone-less contact is never dialed"** bug: see [web-funnel-app.md](../../../../standalone/apps/bdr/features/web-funnel-app.md) and [vapi-webhook-handler.md](../../worker2/features/vapi-webhook-handler.md).
|
|
56
56
|
- **Suggested platform fix (deferred to its own PR/ticket):** gate the `4985–4996` injection to **true reverse / has-many** relations only, so a forward singular-FK child keeps its single-key forced-MATCH; confirm `RecordFields.childPolicy` for `Contacts.primaryContactPhoneNumberId` when fixing. Until then the caller-side workaround is a follow-up identifier-only `PUT` re-link with a self-heal that detects the null/mismatched echo (shipped on the BDR funnel side — see web-funnel-app.md).
|
|
57
57
|
|
|
58
58
|
**⚠ CREATE path: a nested singular FK is matched TENANT-WIDE by VALUE and RE-PARENTED.** The forward-singular-FK back-reference machinery has a second, worse manifestation — on the **CREATE** path, and the damage is a **stolen child row** rather than a null pointer. A nested `primaryContactEmailAddress` / `primaryContactPhoneNumber` object is matched **across the whole tenant by its VALUE** (`emailAddress` / `phoneNumber`) — **not** by `uuid` — and the matched child's back-reference `contactId` is then **flipped to the newest writer**, silently detaching it from its previous owner. **Measured on beta `Client_Aig` 2026-08-17 (TRUE-80562).** Two sequential POSTs each created a new Contact (**854** at 10:19, **856** at 10:41). Afterwards: Contacts **854 AND 856** both have `primaryContactEmailAddressId = 250` and `primaryContactPhoneNumberId = 18`; `ContactEmailAddresses` row **250** has `contactId = 856`; so contact **854 still points at a child row that now belongs to contact 856** — 854's primary email is effectively **detached**. **Singular and collection paths DIVERGE — only the forward singular FK re-parents.** The collection members were **not** stolen: the nested `contactEmailAddresses` entries produced rows **251/252** owned by 854 and **separate new rows 255/256** owned by 856. Same payload, same request — different behavior per path.
|
|
@@ -212,5 +212,5 @@ behaviour — it bites any write to a nested child, not one feature. Worked exam
|
|
|
212
212
|
- [assetType from NetSuite itemtype](../../../1.0/apps/library/features/netsuite-item-assettype-sync.md)
|
|
213
213
|
- [Per-currency amount lines editor](../../toga2-supply/features/currency-amount-lines-editor.md)
|
|
214
214
|
- [cXML ShipNotice Gateway](cxml-shipnotice-gateway.md)
|
|
215
|
-
- [BDR web-funnel app](
|
|
215
|
+
- [BDR web-funnel app](../../../../standalone/apps/bdr/features/web-funnel-app.md) / [VAPI webhook handler](../../worker2/features/vapi-webhook-handler.md)
|
|
216
216
|
- [Client schema-drift audit](../../dbchanges2/workflows/client-schema-drift-audit.md)
|
|
@@ -27,8 +27,8 @@ related:
|
|
|
27
27
|
- ../workflows/dynamic-publish-pipeline.md
|
|
28
28
|
- ../workflows/local-link-into-a-consumer-app.md
|
|
29
29
|
- ../../toga25-supply/features/talos-integration.md
|
|
30
|
-
-
|
|
31
|
-
-
|
|
30
|
+
- ../../../../standalone/apps/bdr/features/landing-chat-drawer.md
|
|
31
|
+
- ../../../../standalone/apps/talos/features/chat-frontend.md
|
|
32
32
|
---
|
|
33
33
|
|
|
34
34
|
Shared pure-UI AI-assistant (launcher + docked/drawer chat panel, adapter-injected, fully tokenized); open for its adapter/controlled contracts, streaming limits, branch divergence, and the per-role message-field gotcha.
|
|
@@ -109,7 +109,7 @@ onSend: (text: string) => Promise<TalosResponse> // resolves ONCE, with the fi
|
|
|
109
109
|
|
|
110
110
|
`TalosMessageModel` / `TalosConversation` are documented "in-memory only". There is **no token delta, no `threadId`, no tool-call surface, and no interrupt representation** anywhere in `types.ts`.
|
|
111
111
|
|
|
112
|
-
**So token streaming is NOT an adapter-implementation detail.** No adapter, however clever, can stream through a `Promise<TalosResponse>` — the promise resolves once. Wiring the live Aegra/LangGraph backend (which streams tokens, emits tool calls, surfaces HITL interrupts — see [Talos chat frontend](
|
|
112
|
+
**So token streaming is NOT an adapter-implementation detail.** No adapter, however clever, can stream through a `Promise<TalosResponse>` — the promise resolves once. Wiring the live Aegra/LangGraph backend (which streams tokens, emits tool calls, surfaces HITL interrupts — see [Talos chat frontend](../../../../standalone/apps/talos/features/chat-frontend.md)) means changing this component's props. That was accepted deliberately rather than shipping a non-streaming v1.
|
|
113
113
|
|
|
114
114
|
### Controlled mode — BUILT 2026-09-01 (the TRUE-80692 contract change)
|
|
115
115
|
|
|
@@ -185,7 +185,7 @@ So the launcher was **already painted under the backdrop and its clicks were alr
|
|
|
185
185
|
- **A `renderMessages`-style slot can silently delete panel-synthesized UI.** The loading bubble is not in `messages`; it was lost exactly this way. Check what the panel mixes into a list before replacing that list.
|
|
186
186
|
- **`onSend` cannot stream** — use **controlled mode** (above). A live streaming backend needs the controlled props, not a cleverer adapter.
|
|
187
187
|
- **Tool calls and HITL interrupts still have no representation** in `TalosMessageModel`. A host mapping from LangGraph must drop them. Surfacing them needs new blox props.
|
|
188
|
-
- The real chat backend is a later blox ticket — `onSend` is stubbed here; do not assume live responses from blox alone. **A working implementation exists outside blox and is now wired to this component:** `bdr/src/lib/talosChat.ts` implements the same `onSend(text) => Promise<TalosResponse>` seam against the live Talos campaign-chat backend (session token, fingerprint, strict message shaping, offline fallback) and plugs straight in — see [AI-BDR landing chat drawer](
|
|
188
|
+
- The real chat backend is a later blox ticket — `onSend` is stubbed here; do not assume live responses from blox alone. **A working implementation exists outside blox and is now wired to this component:** `bdr/src/lib/talosChat.ts` implements the same `onSend(text) => Promise<TalosResponse>` seam against the live Talos campaign-chat backend (session token, fingerprint, strict message shaping, offline fallback) and plugs straight in — see [AI-BDR landing chat drawer](../../../../standalone/apps/bdr/features/landing-chat-drawer.md). **The seam held: no bridge/translation layer was needed.** Consider upstreaming it when the adapter ticket is picked up; the only env-ism to change is its Next-specific `process.env.NEXT_PUBLIC_TALOS_API_BASE` default, which becomes a required `baseUrl` option for Vite consumers.
|
|
189
189
|
- **BDR consumes this component today, but only through a local link.** The React `^18` peer cap is not a hard blocker in practice — BDR (React 19.2.4) runs it via a junction-linked checkout with a single React (procedure: [Local-linking blox into a consumer app](../workflows/local-link-into-a-consumer-app.md); framer-motion 11 and Pro FontAwesome behave fine on React 19). **What is still blocked is deployment:** BDR cannot ship until this branch merges and publishes and BDR consumes the npm version.
|
|
190
190
|
- **Hosts can import the Talos subpath to avoid the barrel's CSS.** `@agilant/toga-blox/dist/components/Talos/index.js` resolves (package `exports` allows `./dist/*`); importing the package barrel pulls **every** blox component's CSS into the consumer bundle.
|
|
191
191
|
- **⚠ `dist/` must be REBUILT for a blox change to reach any browser — and a green consumer typecheck does NOT prove it did.** The consumer's `tsc` resolves blox **types from source** through the `node_modules` symlink, but Vite loads the package at **runtime from `dist/`**. So `tsc --noEmit` can be perfectly clean while the browser runs stale blox code. Every blox change needs `npm run build` in the blox repo **plus** `rm -rf node_modules/.vite` in the consumer. See [Local-linking blox into a consumer app §4](../workflows/local-link-into-a-consumer-app.md). **Correction:** an earlier note claimed blox `npm run build` fails on a missing `tsconfig.app.json` — it does not; it builds fine.
|
|
@@ -198,4 +198,4 @@ So the launcher was **already painted under the backdrop and its clicks were alr
|
|
|
198
198
|
|
|
199
199
|
- [TableRecordModal](table-record-modal.md) — sets the `data-blox-modal-open` marker the launcher dims on.
|
|
200
200
|
- [Dynamic npm Publish Pipeline](../workflows/dynamic-publish-pipeline.md) and [Local-linking blox](../workflows/local-link-into-a-consumer-app.md) — how consumers get Talos.
|
|
201
|
-
- [toga25-supply Talos integration](../../toga25-supply/features/talos-integration.md), [AI-BDR landing chat drawer](
|
|
201
|
+
- [toga25-supply Talos integration](../../toga25-supply/features/talos-integration.md), [AI-BDR landing chat drawer](../../../../standalone/apps/bdr/features/landing-chat-drawer.md), [Talos chat frontend](../../../../standalone/apps/talos/features/chat-frontend.md).
|
|
@@ -18,7 +18,7 @@ related:
|
|
|
18
18
|
- ./dynamic-publish-pipeline.md
|
|
19
19
|
- ../features/talos-assistant.md
|
|
20
20
|
- ../architecture.md
|
|
21
|
-
-
|
|
21
|
+
- ../../../../standalone/apps/bdr/features/landing-chat-drawer.md
|
|
22
22
|
- ../../toga25-supply/features/talos-integration.md
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ How to develop an unpublished blox against a real consumer on Windows (incl. a R
|
|
|
26
26
|
|
|
27
27
|
## Summary
|
|
28
28
|
|
|
29
|
-
How to develop a **blox component that is not published yet** against a real consuming app, on Windows, including the hard case: a **React 19 / Next.js (Turbopack)** host consuming a blox whose peers cap React at `^18`. Proven 2026-08-27 wiring blox `Talos` into `ai-bdr` ([landing-chat-drawer.md](
|
|
29
|
+
How to develop a **blox component that is not published yet** against a real consuming app, on Windows, including the hard case: a **React 19 / Next.js (Turbopack)** host consuming a blox whose peers cap React at `^18`. Proven 2026-08-27 wiring blox `Talos` into `ai-bdr` ([landing-chat-drawer.md](../../../../standalone/apps/bdr/features/landing-chat-drawer.md)).
|
|
30
30
|
|
|
31
31
|
Use it for the inner loop only. **It is not a deploy path** — see [Dynamic npm Publish Pipeline](./dynamic-publish-pipeline.md) for how the consumer eventually gets the code.
|
|
32
32
|
|
|
@@ -204,4 +204,4 @@ So `tsc` can be completely clean while the browser runs **stale** blox code —
|
|
|
204
204
|
- [dynamic-publish-pipeline](./dynamic-publish-pipeline.md) — how the consumer gets blox for real (not this dev loop).
|
|
205
205
|
- [Talos assistant](../features/talos-assistant.md) — the component this loop was proven on.
|
|
206
206
|
- [architecture](../architecture.md) — library overview.
|
|
207
|
-
- [AI-BDR landing chat drawer](
|
|
207
|
+
- [AI-BDR landing chat drawer](../../../../standalone/apps/bdr/features/landing-chat-drawer.md), [toga25-supply Talos integration](../../toga25-supply/features/talos-integration.md).
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
| [Side navigation & default route — an empty nav renders a BLANK PAGE and gets reported as "cannot log in"](features/side-navigation-and-default-route.md) | 2.5 nav/routes/landing are 100% backend-driven by the `navigation` surface; a user with zero visible nav elements gets a BLANK page reported as "can't log in" — |
|
|
18
18
|
| [SSO redirect & public-vs-user session gating (useAuthenticationFlow)](features/sso-redirect-and-session-gating.md) | How 2.5 decides on every navigation whether to bounce an anonymous visitor to their client's SSO IdP vs the local `/login` (useAuthenticationFlow); open for SSO |
|
|
19
19
|
| [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The FE consumer of the platform-wide Surface layer (DB-driven UI config via `GET /v2/surfaces/meta`) — hooks, registries, adapter seams, migration recipe, and t |
|
|
20
|
-
| [Talos Integration
|
|
20
|
+
| [Talos Integration in TOGa Supply](features/talos-integration.md) | TOGa Supply embeds a surface-gated blox Talos panel using the current Supply user's bearer; open for assistant discovery, streaming, frontend lifecycle gaps or |
|
|
21
21
|
| [Toolbar button chrome (ToolbarButton) — and why blox BaseButton can't be resized from the theme](features/toolbar-button-chrome.md) | toga25-supply's own ToolbarButton chrome (pill/chip, both pinned 27px) for page-toolbar buttons, because blox `BaseButton` sizes are un-themeable literals; open |
|
|
22
22
|
| [Transfer Orders page (TableView → Core surfaces → React page + record modal)](features/transfer-orders-page.md) | The Transfer Orders vertical — list + record modal + Create modal, built surface-first from nothing (NYCHH-only today); the cleanest worked example of the curre |
|
|
23
23
|
| [AWS Amplify Multi-Environment Deployment](workflows/amplify-deployment.md) | How toga25-supply deploys to all its Amplify environments from one shared `amplify.yml` — branch `_<mode>` → Vite `--mode`; open when adding an environment or d |
|
|
@@ -1,187 +1,85 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Talos Integration
|
|
2
|
+
title: Talos Integration in TOGa Supply
|
|
3
3
|
framework: "2.0"
|
|
4
4
|
repo: toga25-supply
|
|
5
5
|
project: TOGa 2.5 Supply
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
10
|
-
owners: [apeterson]
|
|
9
|
+
updated: 2026-10-08
|
|
10
|
+
owners: [apeterson, akhokhani]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/api/talos.ts
|
|
13
13
|
- toga25-supply/src/hooks/useTalosSession.ts
|
|
14
14
|
- toga25-supply/src/hooks/useTalosThreads.ts
|
|
15
15
|
- toga25-supply/src/hooks/useTalosSurface.ts
|
|
16
|
-
- toga25-supply/src/App.tsx
|
|
17
16
|
- toga25-supply/src/providers/TalosStreamProvider.tsx
|
|
18
17
|
- toga25-supply/src/utils/talosMessages.ts
|
|
19
|
-
- toga25-supply/src/utils/talosMessages.test.ts
|
|
20
18
|
- toga25-supply/src/layout/AppLayout/AppLayout.tsx
|
|
21
|
-
- toga25-supply
|
|
22
|
-
- toga25-supply/src/index.css
|
|
19
|
+
- toga25-supply/.env.production
|
|
23
20
|
related:
|
|
24
21
|
- ../../toga-blox/features/talos-assistant.md
|
|
25
|
-
- ../../toga-blox/features/table-record-modal.md
|
|
26
|
-
- ./surface-frontend.md
|
|
27
22
|
- ../../dbchanges2/features/surface-layer-schema.md
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
- ../../../standards/frontend.md
|
|
23
|
+
- ../../../../standalone/apps/talos-backend/workflows/toga-supply-client-onboarding.md
|
|
24
|
+
- ../../../../standalone/apps/talos/features/chat-frontend.md
|
|
25
|
+
- ../../../../clients/nychh/features/talos-assistant-enablement.md
|
|
26
|
+
- ../../../../clients/compass-usa/features/talos-supply-assistant.md
|
|
33
27
|
---
|
|
34
28
|
|
|
35
|
-
|
|
29
|
+
TOGa Supply embeds a surface-gated blox Talos panel using the current Supply user's bearer; open for assistant discovery, streaming, frontend lifecycle gaps or tenant enablement.
|
|
36
30
|
|
|
37
31
|
## Summary
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
**⚠ Corrected 2026-09-02 — Talos is NO LONGER enabled for all clients.** It is now gated by the **surface layer**, seeded **OFF for every client**, and opted in per tenant. **NYCHH is the only tenant granted it today.** The suggestion chips come from the same surface, not from blox.
|
|
42
|
-
|
|
43
|
-
As of **2026-09-01 the live Aegra/LangGraph streaming backend is BUILT** (TRUE-80693). `onSend` is no longer a stub — the panel runs in blox's new **controlled mode** and the stream lives in a supply-owned provider. All LangChain code is **app-local**; blox stays pure UI.
|
|
33
|
+
`AppLayout` hosts the launcher and controlled panel; one Supply-owned `TalosStreamProvider` wraps LangGraph SDK `useStream`. Blox is UI only. The shared `talos-assistant` Surface is seeded off and granted per tenant; a provisioned backend assistant does not establish that a customer's panel is enabled.
|
|
44
34
|
|
|
45
35
|
## How it works
|
|
46
36
|
|
|
47
|
-
|
|
48
|
-
src/api/talos.ts — sole VITE_TALOS_API read chokepoint + assistants lookup
|
|
49
|
-
src/hooks/useTalosSurface.ts — DB feature gate + suggestion chips (surface bundle)
|
|
50
|
-
src/hooks/useTalosSession.ts — resolves token + assistantId → a `connection` state
|
|
51
|
-
src/hooks/useTalosThreads.ts — Aegra thread list → blox TalosThreadSummary[] + title polling
|
|
52
|
-
src/providers/TalosStreamProvider.tsx — the single useStream() call, exposed via own context
|
|
53
|
-
src/utils/talosMessages.ts — LangGraph Message[] → blox TalosMessageModel[]
|
|
54
|
-
src/layout/AppLayout/AppLayout.tsx — host: provider wrapper + controlled panel props
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### `src/api/talos.ts` — the env chokepoint
|
|
58
|
-
|
|
59
|
-
The only place `VITE_TALOS_API` is read. Exposes `getTalosApiUrl()`, `isTalosConfigured()`, `fetchTalosAssistants()`, `pickTalosAssistant()`.
|
|
60
|
-
|
|
61
|
-
`fetchTalosAssistants()` **logs the HTTP status before throwing** — `401` = token/issuer mismatch, `403` = tenant not provisioned. Without that log React Query reduces both to a silent boolean and you debug blind.
|
|
62
|
-
|
|
63
|
-
**Do NOT send a body or a `Content-Type` on the `GET /assistants` call.** `fetch` forbids a body on GET, and a JSON content-type only adds a CORS preflight. (The curl example circulated internally used `--data '{}'`; do not copy it into the browser client.)
|
|
64
|
-
|
|
65
|
-
### `assistantId` is PER-TENANT — fetch it, never pin it in env
|
|
66
|
-
|
|
67
|
-
`GET {aegra}/assistants?limit=100&offset=0` with the bearer returns:
|
|
68
|
-
|
|
69
|
-
```jsonc
|
|
70
|
-
{ "assistants": [ { "assistant_id": "…", "name": "…", "graph_id": "…",
|
|
71
|
-
"metadata": { "customer_facing": true, "read_only": true, "tenant_slug": "…" } } ],
|
|
72
|
-
"total": 1 }
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
NYCHH returns exactly one — name `TOGa Supply`, `graph_id: deep_agent`, `read_only: true`, `customer_facing: true`.
|
|
76
|
-
|
|
77
|
-
**Selection rule (`pickTalosAssistant`):** prefer `metadata.customer_facing === true`; else fall back to the full list; take the first; `console.warn` when there is more than one candidate. Never silently pick, never throw.
|
|
78
|
-
|
|
79
|
-
**Design consequence:** `useStream` takes **both** the token and `assistantId` as *values*, so there are now **two** async prerequisites that must resolve above the hook. That is why the panel's `connection` prop is load-bearing rather than polish.
|
|
80
|
-
|
|
81
|
-
### `useTalosSession()` — the gate
|
|
82
|
-
|
|
83
|
-
Returns `connection: "disabled" | "connecting" | "ready" | "error"` plus the token and assistantId.
|
|
84
|
-
- **Gate on `isAuthenticated` (the `"user"` key), NOT on the presence of an accessToken.** blox `fetchPublicToken` leaves a **public** token in storage for logged-out visitors, so "there is a token" is not "there is a user."
|
|
85
|
-
- **Key the assistants query by USER UUID, never by the token.** Supply persists the React Query cache to `localStorage` (`supply-chain-query-cache`), so a token in a query key gets written to disk.
|
|
86
|
-
- `staleTime: Infinity`, `gcTime: Infinity`, `retry: false`.
|
|
87
|
-
- **Anti-pattern — do not gate with `useSuspenseQuery`/Suspense.** It suspends the subtree, so the panel **unmounts and remounts** — flashing and dropping whatever the user typed in the composer. Keep it a plain query and gate on the returned `connection`.
|
|
88
|
-
|
|
89
|
-
### `TalosStreamProvider` — outer gate + inner session
|
|
90
|
-
|
|
91
|
-
One `useStream` call from `@langchain/langgraph-sdk/react`, exposed through a supply-owned context. `threadId` lives in the URL via react-router `useSearchParams` (**never `nuqs`** — Next-only).
|
|
92
|
-
|
|
93
|
-
It is deliberately **split in two**: an outer gate component and an inner `TalosStreamSession`. Hooks cannot be called conditionally, and the stream must not mount until the token *and* the assistantId are real values — so the gate renders the session only once both resolve.
|
|
37
|
+
### Source, environment and request boundary
|
|
94
38
|
|
|
95
|
-
|
|
39
|
+
Use the locally saved `origin/_production` source, not a stale working clone. The October 7 survey inspected Supply commit `bb35181`: React 18.3, Vite 7, LangGraph SDK `^1.10.0` and blox `1.1.4-production.196`. `.env.production` is tracked and sets `VITE_TALOS_API=https://api.togaiq.com`; non-production env files target `https://api.beta.togaiq.com`. There is a production backend.
|
|
96
40
|
|
|
97
|
-
|
|
41
|
+
`src/api/talos.ts` is the only env read chokepoint. Browser requests go directly to Aegra using the current Supply access token and real browser Origin; there is no token exchange or Next proxy. Aegra's TogaHub auth resolves the exact JWT client slug into the Talos control plane; `/v2/users/me` supplies persona-linked AI-model slug grants. The platform MCP receives that same user's bearer and trusted frontend routing context; api2 remains the business-record/field authorization authority.
|
|
98
42
|
|
|
99
|
-
`
|
|
43
|
+
`useTalosSession` requires `isAuthenticated`, not merely a token (logged-out public tokens exist). Assistant query keys use user UUID, never the token: React Query cache is persisted locally. Query state produces disabled/connecting/ready/error; keep it a non-Suspense query so reconnect does not unmount the composer.
|
|
100
44
|
|
|
101
|
-
|
|
45
|
+
`GET /assistants?limit=100&offset=0` discovers the client assistant. Prefer `metadata.customer_facing===true`, otherwise use the list, choose first, and warn on multiple candidates. Never pin an assistant ID in env. GET carries no body or unnecessary JSON Content-Type. HTTP status logs distinguish rejected identity/tenant/entitlement from absent configuration.
|
|
102
46
|
|
|
103
|
-
###
|
|
47
|
+
### Surface and provider lifecycle
|
|
104
48
|
|
|
105
|
-
|
|
49
|
+
`useTalosSurface` finds a `featureEnabled` element in the `talos-assistant` bundle; missing/loading/failed/no-marker means disabled. Its `suggestion` element owns the whole ordered chip row. `config.items` has label/prompt/icon; prompt falls back to label. Invalid items are skipped, while a visible empty row is permitted.
|
|
106
50
|
|
|
107
|
-
|
|
108
|
-
|---|---|
|
|
109
|
-
| `config.role = 'featureEnabled'`, `config.key = 'feature'` | **master switch** — its `isVisible` turns the launcher, the panel and the Aegra stream on or off |
|
|
110
|
-
| `config.role = 'suggestion'`, `config.key = 'suggestions'` | **the whole chip row in ONE element.** `config.items` is an ordered array of `{label, prompt, icon}` (`icon` = a literal FontAwesome name). Its `isVisible` switches the entire row. |
|
|
51
|
+
The outer provider gate waits for enabled Surface, authenticated token and resolved assistant. The inner session owns the single `useStream` above the router outlet, so navigation does not recreate the conversation. Thread ID is URL state via React Router `useSearchParams`, not Next-only nuqs. `talosMessages` maps LangGraph to blox models; tool-call/HITL payloads are not rendered as general user chat.
|
|
111
52
|
|
|
112
|
-
|
|
53
|
+
The inspected implementation shows final-answer outcomes and suppresses final-answer content after failed/cancelled runs. It supports thread list/title polling and metadata writes with `If-Match`. That code alone does not satisfy all backend recovery requirements.
|
|
113
54
|
|
|
114
|
-
|
|
55
|
+
### Backend contract versus inspected gaps
|
|
115
56
|
|
|
116
|
-
`
|
|
57
|
+
The intended embedded-chat contract requires explicit server cancellation, persisted `/transcript` reload, run-ID rejoin with replay cursor, meaningful terminal-state handling, feedback and refreshed bearer retry. In the inspected production provider, Stop calls only `stream.stop()`; the dedicated cancellation helper is not wired. The saved Compass handoff also identified missing persisted transcript reload and run-ID rejoin. Treat these as release gaps, not finished behavior.
|
|
117
58
|
|
|
118
|
-
|
|
59
|
+
The backend assistant is `toga-supply` on `deep_agent`, with user-bearer `toga-platform` tools and tenant-specific persona/BLP. Compass and NYCHH backend deployments existed in the dated survey; neither tenant's current production Surface grants were read from Core/Client DB during that survey. See their client pages for exact evidence.
|
|
119
60
|
|
|
120
|
-
|
|
61
|
+
### Hosting evidence
|
|
121
62
|
|
|
122
|
-
|
|
63
|
+
As of 2026-10-07, production Supply used Amplify app `d3v9s1i7kge4ll` and its CloudFront distribution. `*.beta.togasupply.com` used a different Amplify app/repo, `toga2-supply`, not this production 2.5 source. Confirm hostname→build mapping before reproducing a version-specific failure.
|
|
123
64
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Maps Aegra `AegraThread` rows → blox `TalosThreadSummary[]` (`{ id, title, updated }`); the provider exposes `threads` / `threadsStatus` / `activeThreadId` / `selectThread` and `AppLayout` passes them straight into the panel's data-driven drawer props.
|
|
127
|
-
|
|
128
|
-
**Refresh fires on two edges, and both are needed:**
|
|
129
|
-
1. **On `threadId` assignment.** The server creates the thread at the **START** of the first run, so without this the *currently active* chat is missing from its own drawer.
|
|
130
|
-
2. **On the falling edge of a run** (streaming → idle).
|
|
131
|
-
|
|
132
|
-
**Opening an existing thread needs NO transcript parser.** `@langchain/langgraph-sdk`'s **`setThreadId`** (`dist/ui/orchestrator.js`, `#fetchHistoryForThread`) **clears the stream and fetches that thread's history itself** when `fetchStateHistory: true`. So selecting a history row is just "set the threadId", and the existing LangGraph→blox mapper handles the rest. This took `fromTalosTranscript()` **off the critical path for history**. It is still needed for the durable message ids that feedback requires — do not delete it.
|
|
133
|
-
|
|
134
|
-
**Auto-title polling — `titlePollInterval`.** Aegra names a thread **asynchronously after the first run** and emits **no SSE event**, so the only way to see a title is to ask again. `titlePollInterval` feeds React Query's `refetchInterval`: **4s while any RECENT thread is unnamed, `false` otherwise.** Two deliberate deviations from the handoff doc §8.10:
|
|
135
|
-
- The doc says poll *"while the first run is active"*. **The title lands AFTER the run**, so polling only during it usually misses it entirely.
|
|
136
|
-
- Added a **2-minute age window** the doc does not specify. A thread whose first message was never text-bearing **never gets named at all**, so "stop when the title arrives" on its own polls every 4s for the whole session.
|
|
137
|
-
|
|
138
|
-
7 tests cover the stop condition, including a server clock running ahead of the client.
|
|
139
|
-
|
|
140
|
-
> Server-side, auto-naming is currently **off or broken** for NYCHH's assistant, so this polling has nothing to find yet — see [aegra-api](../../talos/features/aegra-api.md). Supply reads `metadata.thread_name` correctly and cannot fix it.
|
|
141
|
-
|
|
142
|
-
### `talosMessages.ts` — the LangGraph → blox mapper
|
|
143
|
-
|
|
144
|
-
- Handles LangGraph's **string-OR-content-blocks** union for `content`.
|
|
145
|
-
- Filters to `human` / `ai` only — `system`, `tool` and `remove` are dropped.
|
|
146
|
-
- An **empty AI turn becomes `{ thinking: true }`** (the stream opening). An empty human turn is dropped.
|
|
147
|
-
- Streamed text goes to **`message`** (light markdown), *not* `paras`: during a stream the text is partial, and splitting it into finished paragraphs reflows the bubble on every token.
|
|
148
|
-
- **Deliberate loss:** tool calls and HITL interrupts have **no representation** in `TalosMessageModel` and are dropped. Surfacing them needs new blox props — not a mapper change.
|
|
149
|
-
|
|
150
|
-
13 unit tests in `src/utils/talosMessages.test.ts`.
|
|
151
|
-
|
|
152
|
-
### The `talos` query namespace is EXCLUDED from the persisted cache (2026-09-02)
|
|
153
|
-
|
|
154
|
-
`App.tsx`'s `PersistQueryClientProvider` used to persist **every** query to `localStorage`. A `shouldDehydrateQuery` filter now excludes the **`talos`** namespace alongside `surface-meta` / `surface-meta-group`: chat titles and assistant ids are **user/session data that must not outlive the session on disk**. The surface half of the same fix is what makes a Talos grant (or a **revoke**) actually reach a running browser — see [surface-frontend](./surface-frontend.md).
|
|
155
|
-
|
|
156
|
-
### Environment config
|
|
157
|
-
|
|
158
|
-
`VITE_TALOS_API` is set to `https://api.beta.togaiq.com` in **7 non-prod env files**. It is left **commented out in `.env` (production)** because no live production Aegra host is confirmed — `isTalosConfigured()` therefore returns false there and `connection` resolves to `"disabled"`.
|
|
159
|
-
|
|
160
|
-
### Package choice: `@langchain/langgraph-sdk/react`, app-local
|
|
161
|
-
|
|
162
|
-
- **`useStream` from `@langchain/langgraph-sdk/react`** — the same import talos uses — **not `@langchain/react`.** The decision stands: the path is proven in-house so `talos/src/providers/Stream.tsx` lifts nearly verbatim, and `@langchain/react`'s extra surface is largely **media hooks/players** blox has no components to render.
|
|
163
|
-
- **⚠ Correction (verified 2026-09-01): the old "one fewer peer" reason was WRONG.** `@langchain/langgraph-sdk@1.10.0` declares `@langchain/core: ^1.1.48` as a **required (non-optional) peer** itself; `react`/`react-dom` are the optional ones. Symptom when it is missing: Vite/esbuild dep-optimize **hard-fails** with `Could not resolve "@langchain/core/messages"` and the dev server exits. Install `@langchain/core` alongside the SDK.
|
|
164
|
-
- **Take only `useStream` for v1.** Add `useToolCalls` when tool activity is actually shown, and the headless interrupt helpers for human-in-the-loop — that is when `@langchain/react` earns its keep.
|
|
165
|
-
- **It stays in supply, never in blox.** Per [frontend.md §21](../../../standards/frontend.md) this is n=1, and per §13(b) a blox peer would force `@langchain/core` on all five consumer apps.
|
|
65
|
+
## Gotchas
|
|
166
66
|
|
|
167
|
-
|
|
67
|
+
- Surface visibility, active `/users/me` slug grant, control-plane tenant, assistant capability assignments and MCP data ACL are independent gates. Do not repair a denied user with an admin/service token.
|
|
68
|
+
- A backend assistant with successful historical runs is not proof of a production panel launch. Read the actual Surface bundle as the intended user.
|
|
69
|
+
- SDK Stop closes browser streaming; it is not a verified server-run cancellation in the inspected implementation.
|
|
70
|
+
- The mapper hides tools/HITL. Keep this customer-facing read-only assistant within its declared boundary; richer decision UI requires deliberate contract work.
|
|
71
|
+
- Stable query keys must not include credentials. Caches and logs can persist long after a token changes.
|
|
72
|
+
- Code comments calling Aegra “TOGa IQ” are legacy naming. Talos is the backend agent platform; TOGa IQ is the separate management UI.
|
|
168
73
|
|
|
169
|
-
|
|
74
|
+
## Related
|
|
170
75
|
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
76
|
+
- [talos assistant](../../toga-blox/features/talos-assistant.md)
|
|
77
|
+
- [surface layer schema](../../dbchanges2/features/surface-layer-schema.md)
|
|
78
|
+
- [toga supply client onboarding](../../../../standalone/apps/talos-backend/workflows/toga-supply-client-onboarding.md)
|
|
79
|
+
- [chat frontend](../../../../standalone/apps/talos/features/chat-frontend.md)
|
|
80
|
+
- [talos assistant enablement](../../../../clients/nychh/features/talos-assistant-enablement.md)
|
|
81
|
+
- [talos supply assistant](../../../../clients/compass-usa/features/talos-supply-assistant.md)
|
|
174
82
|
|
|
175
|
-
##
|
|
83
|
+
## Change history
|
|
176
84
|
|
|
177
|
-
-
|
|
178
|
-
- **user turns use `text`, Talos turns use `message`/`paras`.** blox `TalosMessage` renders **`message.text` for a `role: "user"` turn** but **`message.message` / `message.paras` for a `role: "talos"` turn**. The mapper originally put user turns in `message`, which renders an **empty bubble**. Caught only by writing the tests.
|
|
179
|
-
```ts
|
|
180
|
-
// CORRECT
|
|
181
|
-
{ role: "user", text } // user turn
|
|
182
|
-
{ role: "talos", message } // assistant turn
|
|
183
|
-
```
|
|
184
|
-
Anyone writing to `TalosMessageModel` by hand will hit this.
|
|
185
|
-
- **The launcher greys out under a modal via a ROOT ATTRIBUTE, and keyboard access is still open.** blox `TableRecordModal` sets **`data-blox-modal-open` on `document.documentElement`** while open, and blox dims the launcher under `:root[data-blox-modal-open]`. It applies to **every** `TableRecordModal` in supply automatically — do not add a per-page dim. Why an attribute and not a prop: the launcher renders in the **header**, outside the modal's subtree, so no shared React state reaches it (same boundary-crossing trick as `--talos-dock-width`). Mechanism + the counter it needs: [TableRecordModal](../../toga-blox/features/table-record-modal.md). 🚨 **Known gap, unfixed:** the launcher is still **keyboard-reachable** behind a modal. `pointer-events: none` stops the mouse only. Supply's header receives `inert` for the **side nav** but **not** for modals — closing this is a **supply** change that affects every header control, so it was flagged rather than patched.
|
|
186
|
-
- **Reserve dock width on the OUTER wrapper, not just `<main>`.** The docked panel is `position: fixed`, full-height on the right. The blox `Header` is in **normal document flow** (NOT fixed). Reserving the dock width only on `<main>` leaves the header's right edge sitting **under** the panel, hiding the launcher + avatar. **Fix:** apply the reserved dock width (`marginRight` = the `onDockWidthChange` value) to the **outer app wrapper**.
|
|
187
|
-
- **`npm install` silently un-links blox and Talos disappears.** Any `npm install` in this repo replaces the `node_modules/@agilant/toga-blox` **symlink** with the registry version, which contains no Talos. The symptom looks nothing like a dependency problem. Full symptom + relink recipe: [Local-linking blox into a consumer app §1a](../../toga-blox/workflows/local-link-into-a-consumer-app.md).
|
|
85
|
+
- 2026-10-08 — Reconciled local source and dated 2026-10-07 research into the canonical KB (akhokhani).
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
| [Stranded WorkerJobs (deploy-window job loss) and how to repair them](features/stranded-worker-jobs.md) | Jobs queued while worker2 restarts are dropped silently with no retry and no alert; open when a cron "never ran" or a webhook vanished. |
|
|
61
61
|
| [Talos Meeting-Notes Integration & Token Auto-Refresh (consumer)](features/talos-meeting-notes-integration.md) | Consumer side of Talos: the endpoints, DevCore assistant, and JWT auto-refresh a worker2 dev tool needs to query the meeting-notes corpus; open when a tool must |
|
|
62
62
|
| [Talos Pricing Automation (worker2 Cron — Usage Import, AWS Actuals, Margins, Profiles)](features/talos-pricing-automation.md) | Monthly worker2 crons that turn raw usage + AWS cost into a measured platform unit price, per-client cost, and margins; open for the pricing pipeline, its AWS c |
|
|
63
|
+
| [Pricing & COGS Model (Talos Pricing Calculator)](features/talos-pricing-cogs-model.md) | Cost basis + pricing methodology for selling Talos chat and voice; open to re-price Talos or understand COGS drivers, token rates, and the band/org-fee model. |
|
|
63
64
|
| [Talos Transcript Ingestion Pipeline (worker2 → AWS Bedrock KBs)](features/talos-transcript-ingestion.md) | `_Worker_Team_Transcripts` cron pipeline ingesting Teams VTT transcripts into Talos Bedrock KBs + emailing organizer recaps; open for Export/Process/Retry/SyncK |
|
|
64
65
|
| [Team Sprint Management & Reporting](features/team-sprint-management.md) | `_Worker_Team_Sprint` engine for TOGA's biweekly dev-sprint process + reporting (warnings, lock, daily dashboard, sprint-end scoring, AI release notes, 7 PM In |
|
|
65
66
|
| [Teams Meeting Transcript Export](features/teams-transcript-export.md) | How `Team/Transcripts/Export` polls Microsoft Graph for Teams transcripts; open for the Graph organizer-resolution, GUID-vs-UPN, and Entra-permission details (t |
|
|
@@ -14,9 +14,9 @@ files:
|
|
|
14
14
|
- worker2/Controller/Index.php
|
|
15
15
|
related:
|
|
16
16
|
- vapi-webhook-handler.md
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
17
|
+
- ../../../../standalone/apps/ai-bdr/features/vapi-integration.md
|
|
18
|
+
- ../../../../standalone/apps/ai-bdr/features/call-orchestration.md
|
|
19
|
+
- ../../../../standalone/apps/ai-bdr/workflows/safe-call-loop-testing.md
|
|
20
20
|
---
|
|
21
21
|
|
|
22
22
|
The AI-BDR callback path (prospect says "call me back" → dialer redials) and its production defects; open when working on Vapi callback capture/parse/schedule or the callback root cause.
|
|
@@ -43,14 +43,14 @@ Callback path spans the webhook (`Worker/Vapi.php` — capture, persist, parse,
|
|
|
43
43
|
|
|
44
44
|
### End to end
|
|
45
45
|
|
|
46
|
-
1. **Capture.** Requested time arrives at `message.artifact.structuredOutputs.<schema-uuid>.result.callbackTime` (`Worker/Vapi.php:99` → `:109–122` → `:144`) — **not** in `analysis`, which is always empty. The published schema documents ISO 8601 ([vapi-integration.md](
|
|
46
|
+
1. **Capture.** Requested time arrives at `message.artifact.structuredOutputs.<schema-uuid>.result.callbackTime` (`Worker/Vapi.php:99` → `:109–122` → `:144`) — **not** in `analysis`, which is always empty. The published schema documents ISO 8601 ([vapi-integration.md](../../../../standalone/apps/ai-bdr/features/vapi-integration.md)), but in practice the field is **unconstrained free text**; the file's own sample payload contains `"callbackTime": "later"` (`Worker/Vapi.php:45`).
|
|
47
47
|
2. **Persist (raw).** `updateContactAttempt` stores the string with **no conversion** (`:213–215`) alongside `c_callOutcome='CALLBACK_SCHEDULED'` / `c_actionToTake='SCHEDULE_CALLBACK'` (map at `:161–173`, applied `:189–194`), via `PUT /contact-attempts/{uuid}` (`:256–266`). `c_callbackTime` is `VARCHAR(255)` (dbchanges2 `_modules/Ai/Bdr/2026-03-04 bdrCustomfields.sql:84`), so a malformed value **survives persistence intact** and only dies at the act step.
|
|
48
48
|
3. **Act.** `executePostCallActions` dispatches `SCHEDULE_CALLBACK` → `actionScheduleCallback`, which resolves the campaign timezone (`:400`), calls `self::convertDateTime($callbackTime, …)` (`:401`), and on success writes `Contacts.dtNextContactRequested` (`:414`) and `contactCallTypeId = CALLBACK` (`:417`) via `PUT /contacts/{uuid}` (`:420–430`).
|
|
49
49
|
4. **Redial.** The dialer treats a due `dtNextContactRequested` as the privileged path: it **bypasses call windows, weekly cadence, call-window exception dates and prior DNC** (`Ai/Bdr/Vapi.php:238–303`, `:314–331`). Callbacks also sort first in the per-run queue (`:334`).
|
|
50
50
|
|
|
51
51
|
### Recommended fix direction (decided 2026-07-30 — priority order)
|
|
52
52
|
|
|
53
|
-
1. **DURABLE FIX — Vapi assistant config side.** Constrain `callbackTime` in the structured-output schema to **strict ISO 8601 with offset**, and prompt the assistant to resolve relative speech to an absolute timestamp before emitting. ISO parses cleanly today, so this removes the whole class of failure. See [vapi-integration.md](
|
|
53
|
+
1. **DURABLE FIX — Vapi assistant config side.** Constrain `callbackTime` in the structured-output schema to **strict ISO 8601 with offset**, and prompt the assistant to resolve relative speech to an absolute timestamp before emitting. ISO parses cleanly today, so this removes the whole class of failure. See [vapi-integration.md](../../../../standalone/apps/ai-bdr/features/vapi-integration.md).
|
|
54
54
|
2. **`Worker/Vapi.php:71–79` and `:135`** — add `if (($message->type ?? '') !== 'end-of-call-report') return 'ok';` and stop force-stamping `dtEnded` from `NOW()` (set it only from a real `endedAt`). Independent of the callback bug and arguably **more urgent** — see the concurrency gotcha in [vapi-webhook-handler.md](vapi-webhook-handler.md).
|
|
55
55
|
3. **`:609–635` and `:403–406`** — defensive normalization (strip leading `in `/`at `/`around `/`sometime `, map spelled-out numbers) and, on failure, **schedule a flagged sane default rather than `return`** — never silently drop a promised callback.
|
|
56
56
|
4. **`:401–414`** — clamp the parsed time: if `<= now`, push to the next valid slot; snap into the campaign's call windows; reject beyond ~90 days.
|
|
@@ -174,6 +174,6 @@ A prospect who asks for a callback **on their 3rd attempt** gets `dtNextContactR
|
|
|
174
174
|
## Related
|
|
175
175
|
|
|
176
176
|
- [vapi-webhook-handler](vapi-webhook-handler.md)
|
|
177
|
-
- [vapi-integration](
|
|
178
|
-
- [call-orchestration](
|
|
179
|
-
- [safe-call-loop-testing](
|
|
177
|
+
- [vapi-integration](../../../../standalone/apps/ai-bdr/features/vapi-integration.md)
|
|
178
|
+
- [call-orchestration](../../../../standalone/apps/ai-bdr/features/call-orchestration.md)
|
|
179
|
+
- [safe-call-loop-testing](../../../../standalone/apps/ai-bdr/workflows/safe-call-loop-testing.md)
|
|
@@ -20,7 +20,7 @@ related:
|
|
|
20
20
|
- ./talos-transcript-ingestion.md
|
|
21
21
|
- ./creating-worker-actions.md
|
|
22
22
|
- ../architecture.md
|
|
23
|
-
-
|
|
23
|
+
- ../../../../standalone/apps/talos-backend/features/talos-agent.md
|
|
24
24
|
---
|
|
25
25
|
|
|
26
26
|
Async worker that "fluffs" a new ClickUp task by running its name+description through the Talos `dev-core` KB agent and writing the report back; open for the fluffer flow, the distinct Talos agent endpoint/key, or the open prod 403.
|
|
@@ -99,4 +99,4 @@ Both are separate from the existing `[talos]` `api_key`/`endpoint` (used by Tran
|
|
|
99
99
|
- [Talos transcript ingestion](./talos-transcript-ingestion.md)
|
|
100
100
|
- [Creating Worker Actions](./creating-worker-actions.md)
|
|
101
101
|
- [Worker (worker2) Architecture](../architecture.md)
|
|
102
|
-
- [Talos agent](
|
|
102
|
+
- [Talos agent](../../../../standalone/apps/talos-backend/features/talos-agent.md)
|
|
@@ -11,7 +11,7 @@ owners: [dfranks]
|
|
|
11
11
|
files:
|
|
12
12
|
- .claude/skills/plan-ticket/scripts/talos.js
|
|
13
13
|
related:
|
|
14
|
-
-
|
|
14
|
+
- ../../../../standalone/apps/talos-backend/architecture.md
|
|
15
15
|
- ./clickup-richtext-api.md
|
|
16
16
|
- ../workflows/ticket-to-pseudocode-planning.md
|
|
17
17
|
---
|
|
@@ -20,7 +20,7 @@ Consumer side of Talos: the endpoints, DevCore assistant, and JWT auto-refresh a
|
|
|
20
20
|
|
|
21
21
|
## Summary
|
|
22
22
|
|
|
23
|
-
How a **dev tool / agent consumes Talos** to query the team meeting-notes corpus programmatically. Talos itself (the LangGraph Agent Protocol server) is documented under [`
|
|
23
|
+
How a **dev tool / agent consumes Talos** to query the team meeting-notes corpus programmatically. Talos itself (the LangGraph Agent Protocol server) is documented under [`standalone/apps/talos-backend/architecture.md`](../../../../standalone/apps/talos-backend/architecture.md); this doc is the **consumer side**.
|
|
24
24
|
|
|
25
25
|
**Key distinction:** the `[talos]` key in worker2 config only reaches the **stateless** `/api/ai/generate` and `/api/ai/chat` endpoints, which have **no meeting-notes access**. Meeting-notes access comes only from **assistants wired to knowledge bases**, reached through the Agent Protocol `/threads` + `/threads/{id}/runs/wait` surface with a **user Bearer JWT**.
|
|
26
26
|
|
|
@@ -81,6 +81,6 @@ The consumer tool stores its token pair at **`~/.talos/credentials.json`** (user
|
|
|
81
81
|
|
|
82
82
|
## Related
|
|
83
83
|
|
|
84
|
-
- [Talos architecture](
|
|
84
|
+
- [Talos architecture](../../../../standalone/apps/talos-backend/architecture.md)
|
|
85
85
|
- [ClickUp rich-text API](./clickup-richtext-api.md)
|
|
86
86
|
- [Ticket-to-pseudocode planning workflow](../workflows/ticket-to-pseudocode-planning.md)
|
|
@@ -21,9 +21,9 @@ files:
|
|
|
21
21
|
related:
|
|
22
22
|
- ./creating-worker-actions.md
|
|
23
23
|
- ../architecture.md
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
24
|
+
- ../../../../standalone/apps/talos-backend/architecture.md
|
|
25
|
+
- talos-pricing-cogs-model.md
|
|
26
|
+
- ../../../../1.0/apps/tools/features/talos-pricing-ui.md
|
|
27
27
|
---
|
|
28
28
|
|
|
29
29
|
Monthly worker2 crons that turn raw usage + AWS cost into a measured platform unit price, per-client cost, and margins; open for the pricing pipeline, its AWS cost query, or the `Talos*` Team-DB schema.
|
|
@@ -64,7 +64,7 @@ Untagged spend is attributed to the **defaultTenant**, and every row records `is
|
|
|
64
64
|
|
|
65
65
|
Computes `clientMonthlyCost = client tokens × unitCostPer1kTokens`, margin vs. the client's band, the consecutive out-of-band streak, and emits a `TalosFeeRecommendations` row only once the streak ≥ the client's `consecutiveMonths`. **Internal tenants are excluded from fee recommendations** (see below). The old per-client "calibration factor" is gone.
|
|
66
66
|
|
|
67
|
-
**Per-interaction clients (`pricingModel = PER_INTERACTION`, 2026-09-17):** revenue = `orgFee + interactions × perInteractionFee` (no bands); everything else — the streak, the org-fee recommendation — is identical. This **recurring** margin is the only input to the recommendation/streak. The **blended** margin (`blendedMarginPct`) additionally includes `amortizedFeeMonthly` (the amortized contract fees) and is written for **display only** — never fed to the streak. Design/rationale in [pricing-cogs-model](
|
|
67
|
+
**Per-interaction clients (`pricingModel = PER_INTERACTION`, 2026-09-17):** revenue = `orgFee + interactions × perInteractionFee` (no bands); everything else — the streak, the org-fee recommendation — is identical. This **recurring** margin is the only input to the recommendation/streak. The **blended** margin (`blendedMarginPct`) additionally includes `amortizedFeeMonthly` (the amortized contract fees) and is written for **display only** — never fed to the streak. Design/rationale in [pricing-cogs-model](talos-pricing-cogs-model.md).
|
|
68
68
|
|
|
69
69
|
### 4. RecomputeProfiles (09:00)
|
|
70
70
|
|
|
@@ -111,6 +111,6 @@ The existing `[talos]` config group gains **`usage_url`** and **`usage_api_key`*
|
|
|
111
111
|
|
|
112
112
|
- [Creating worker actions](./creating-worker-actions.md)
|
|
113
113
|
- [Worker (worker2) architecture](../architecture.md)
|
|
114
|
-
- [Talos architecture](
|
|
115
|
-
- [Talos pricing COGS model](
|
|
116
|
-
- [Talos pricing UI (tools)](
|
|
114
|
+
- [Talos architecture](../../../../standalone/apps/talos-backend/architecture.md)
|
|
115
|
+
- [Talos pricing COGS model](talos-pricing-cogs-model.md)
|
|
116
|
+
- [Talos pricing UI (tools)](../../../../1.0/apps/tools/features/talos-pricing-ui.md)
|