toga-ai 1.0.353 → 1.0.355
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.
|
@@ -6,7 +6,7 @@ project: Tools
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-16
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- tools/mvc/talos/kb-documents/get.php
|
|
@@ -97,36 +97,100 @@ false success.
|
|
|
97
97
|
### `POST /talos/knowledge-bases` — create a new KB (synchronous provisioning)
|
|
98
98
|
|
|
99
99
|
Admin action that provisions a brand-new Talos knowledge base end to end in **one
|
|
100
|
-
synchronous request
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
**
|
|
111
|
-
|
|
100
|
+
synchronous request**. The KB is a **classic VECTOR knowledge base backed by Amazon S3
|
|
101
|
+
Vectors** (the canonical design — see the architecture note below), and the flow is now
|
|
102
|
+
**9 steps** across systems with **no shared transaction**:
|
|
103
|
+
|
|
104
|
+
1. **validate slug** (≤255) + derive via **`App_Talos_S3::slugify()`** (kebab-case, `iconv`
|
|
105
|
+
ASCII translit; rejects a duplicate slug — `slug` is UNIQUE).
|
|
106
|
+
2. **S3 folders** — 3 markers `development-team/{slug}/{approved,archive,upload}/` via
|
|
107
|
+
**`App_Talos_S3::putFolderMarker()`**.
|
|
108
|
+
3. **S3 Vectors store** — create a dedicated vector bucket + index via
|
|
109
|
+
`App_Talos_Bedrock::createVectorStore()`, capturing the authoritative **`indexArn`**.
|
|
110
|
+
4. **VECTOR KB** — `createKnowledgeBase($bedrock, $slug, $indexArn)` (VECTOR + `S3_VECTORS`
|
|
111
|
+
storage).
|
|
112
|
+
5. **wait for `ACTIVE`** (`waitForKnowledgeBaseActive`).
|
|
113
|
+
6. **S3 data source** — plain `S3` connector + `BEDROCK_DATA_AUTOMATION` parsing.
|
|
114
|
+
7. **`Team.KnowledgeBases`** (`db_team`, Team MySQL cluster).
|
|
115
|
+
8. **`Client_True.VectorIndexes`** (`db_true`, **Client MySQL cluster** — not the Team cluster).
|
|
116
|
+
9. **2 Talos Postgres rows** (`public.knowledge_bases` + `public.assistant_knowledge_bases`,
|
|
117
|
+
the latter linking a hard-coded assistant id).
|
|
118
|
+
|
|
119
|
+
The create branch sets `set_time_limit(CREATE_MAX_EXECUTION_SECONDS = 600)` up top because the
|
|
120
|
+
flow blocks on multi-minute AWS waits (S3 Vectors index readiness + KB `ACTIVE`, up to ~300s).
|
|
121
|
+
This only prevents the PHP fatal — it does **not** lift the EB Apache `ProxyTimeout` ceiling
|
|
122
|
+
(handled separately in `.platform`, see below). This flow **stays synchronous by design** —
|
|
123
|
+
moving it to worker2/SQS async was explicitly rejected; the fix path is to raise timeouts,
|
|
124
|
+
never to background the work.
|
|
125
|
+
|
|
126
|
+
### Bedrock KB architecture — VECTOR + S3 Vectors (canonical)
|
|
127
|
+
|
|
128
|
+
The canonical Talos KB config (from **`development-team-dunn`**, confirmed identical across
|
|
129
|
+
`development-team-ninja-rmm` and `development-team-warehouse`) is a **classic VECTOR** KB, **not**
|
|
130
|
+
the fully-MANAGED type:
|
|
131
|
+
- **KnowledgeBase:** `knowledgeBaseConfiguration.type = VECTOR`;
|
|
132
|
+
`vectorKnowledgeBaseConfiguration.embeddingModelArn =
|
|
133
|
+
arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v2:0`;
|
|
134
|
+
`embeddingModelConfiguration.bedrockEmbeddingModelConfiguration.embeddingDataType = FLOAT32`;
|
|
135
|
+
`storageConfiguration.type = S3_VECTORS` pointing at the per-KB S3 Vectors index ARN.
|
|
136
|
+
- **S3 Vectors index** (one dedicated vector bucket + index **per KB**): `dimension = 1024`,
|
|
137
|
+
`dataType = float32`, `distanceMetric = euclidean`,
|
|
138
|
+
`metadataConfiguration.nonFilterableMetadataKeys = [AMAZON_BEDROCK_TEXT, AMAZON_BEDROCK_METADATA]`,
|
|
139
|
+
encryption `sseType = AES256` (SSE-S3). Vector bucket name mirrors the console:
|
|
140
|
+
`bedrock-knowledge-base-{slug}`; index name `bedrock-knowledge-base-default-index`.
|
|
141
|
+
- **DataSource:** `dataSourceConfiguration.type = S3` (plain S3 connector);
|
|
142
|
+
`s3Configuration.bucketArn = arn:aws:s3:::togaiq`;
|
|
143
|
+
`inclusionPrefixes = ["development-team/{slug}/approved/"]`;
|
|
144
|
+
`vectorIngestionConfiguration.parsingConfiguration.parsingStrategy = BEDROCK_DATA_AUTOMATION`;
|
|
145
|
+
`dataDeletionPolicy = DELETE`.
|
|
146
|
+
|
|
147
|
+
Account `654654170868`, region `us-east-1`. Verified working end-to-end in production
|
|
148
|
+
(2026-07-16).
|
|
112
149
|
|
|
113
150
|
The handler is **best-effort with no rollback**: on a mid-flow failure it stops and returns
|
|
114
151
|
a `steps[]` report **without tearing down** already-created AWS resources (see Gotchas —
|
|
115
152
|
orphaned KB).
|
|
116
153
|
|
|
117
|
-
**`App_Talos_Bedrock`** (`_/app/talos/bedrock.php`) — Bedrock Agent
|
|
154
|
+
**`App_Talos_Bedrock`** (`_/app/talos/bedrock.php`) — Bedrock Agent + S3 Vectors clients:
|
|
155
|
+
- **`ROLE_ARN`** — the single **shared** execution role
|
|
156
|
+
`arn:aws:iam::654654170868:role/AmazonBedrockExecutionRoleForKnowledgeBase-talos`, hard-coded
|
|
157
|
+
(replaced the old per-KB `_tonej` role). See the IAM prerequisite below.
|
|
158
|
+
- `s3VectorsClient()` — `Aws\S3Vectors\S3VectorsClient`, api version `2025-07-15`, using the same
|
|
159
|
+
`[talos]` credential resolution as `App_Talos_S3::client()`.
|
|
160
|
+
- `vectorBucketName()` — derives `bedrock-knowledge-base-{slug}` and enforces the S3 Vectors
|
|
161
|
+
bucket-name length limit (3–63 chars).
|
|
162
|
+
- `createVectorStore()` — creates the vector bucket + index sized to Titan v2 (dim 1024,
|
|
163
|
+
float32, euclidean), then **polls `getIndex` for the authoritative index ARN** with a short
|
|
164
|
+
`NotFound` retry; returns an actionable error on `Conflict`/`AlreadyExists` from an orphaned
|
|
165
|
+
prior attempt.
|
|
166
|
+
- `createKnowledgeBase($bedrock, string $slug, string $indexArn)` — creates the VECTOR KB with
|
|
167
|
+
`S3_VECTORS` storage (signature now takes the index ARN).
|
|
118
168
|
- `waitForKnowledgeBaseActive()` polls `getKnowledgeBase` every `WAIT_INTERVAL_SECONDS` (3s)
|
|
119
|
-
up to **`WAIT_MAX_SECONDS` = 300
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
169
|
+
up to **`WAIT_MAX_SECONDS` = 300**. Exits immediately on `ACTIVE`/`FAILED`. 300s sits well
|
|
170
|
+
under the 900s Apache/PHP ceiling.
|
|
171
|
+
- `createDataSource()` — plain **`S3`** connector + `BEDROCK_DATA_AUTOMATION` parsing (rewritten
|
|
172
|
+
from the old `MANAGED_KNOWLEDGE_BASE_CONNECTOR`). See the architecture note above for the exact
|
|
173
|
+
shape.
|
|
174
|
+
- The vendored `aws/aws-sdk-php` (`^3.387`) already ships both the `S3Vectors` and `BedrockAgent`
|
|
175
|
+
clients and the `S3_VECTORS` `storageConfiguration` shape (verified against the SDK model). The
|
|
176
|
+
now-dead `BUCKET_NAME` / `BUCKET_OWNER_ACCOUNT_ID` constants were removed.
|
|
177
|
+
|
|
178
|
+
**IAM prerequisites (one-time, manual — the app does NOT provision IAM):**
|
|
179
|
+
- **Shared execution role** `AmazonBedrockExecutionRoleForKnowledgeBase-talos` — one role for
|
|
180
|
+
ALL Talos KBs (decision: do **not** create a role+policies per KB, which would require granting
|
|
181
|
+
the web app IAM write powers — rejected as a security expansion). Has 4 inline policies
|
|
182
|
+
mirroring dunn's but **wildcarded**: s3vectors data-plane on
|
|
183
|
+
`bucket/bedrock-knowledge-base-*/index/*`; `s3:GetObject` on
|
|
184
|
+
`togaiq/development-team/*/approved/*` (+ `s3:ListBucket` on `togaiq`); `bedrock:InvokeModel`
|
|
185
|
+
on `titan-embed-text-v2:0` (+ marketplace); BDA `GetDataAutomationStatus` +
|
|
186
|
+
`InvokeDataAutomationAsync`. Trust policy: `bedrock.amazonaws.com` assume-role with
|
|
187
|
+
`SourceAccount 654654170868` and `SourceArn knowledge-base/*`.
|
|
188
|
+
- **App credential grant** — the `[talos]` app credentials are IAM user
|
|
189
|
+
`arn:aws:iam::654654170868:user/bedrock-model-accessor`. It was granted (new inline policy
|
|
190
|
+
**`TalosKbProvisioning`**) `s3vectors:CreateVectorBucket/CreateIndex/GetIndex` and
|
|
191
|
+
`iam:PassRole` on the shared role. Its bedrock create actions were already covered by
|
|
192
|
+
`AmazonBedrockFullAccess` and S3 by `AmazonS3FullAccess`. **`s3vectors` is a SEPARATE service
|
|
193
|
+
NOT covered by `AmazonBedrockFullAccess`** — that was the real missing grant.
|
|
130
194
|
|
|
131
195
|
## Helpers
|
|
132
196
|
|
|
@@ -200,20 +264,23 @@ orphaned KB).
|
|
|
200
264
|
- **php-fpm `request_terminate_timeout` can still kill the request.** If
|
|
201
265
|
`/etc/php-fpm.d/www.conf`'s `request_terminate_timeout` is ever set to 60 it terminates the
|
|
202
266
|
request regardless of Apache — it must be `0` or `>= 900`.
|
|
203
|
-
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
`
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
267
|
+
- **The Bedrock API does NOT auto-provision the S3 Vectors bucket/index** (the console does).
|
|
268
|
+
They must be created first (`s3vectors CreateVectorBucket` + `CreateIndex`) and the resulting
|
|
269
|
+
index ARN passed into `CreateKnowledgeBase`. `createVectorStore()` handles this before KB
|
|
270
|
+
creation.
|
|
271
|
+
- **`s3vectors` is a separate AWS service** — it is **not** covered by `AmazonBedrockFullAccess`.
|
|
272
|
+
The app credentials need explicit `s3vectors:*` grants (see IAM prerequisite above); this was
|
|
273
|
+
the real missing permission.
|
|
274
|
+
- **KB create has no rollback → orphaned KB risk.** A failure mid-flow can leave an orphaned
|
|
275
|
+
S3 Vectors bucket/index and/or Bedrock KB with **no DB rows** (`Team.KnowledgeBases`/
|
|
276
|
+
`VectorIndexes`/Postgres never inserted). Blindly re-running with the same slug hits
|
|
277
|
+
`Conflict`/`AlreadyExists` on the vector bucket (surfaced as an actionable error) or creates a
|
|
278
|
+
**duplicate** Bedrock KB (Bedrock allows same-name KBs with new ids). After a failed create:
|
|
279
|
+
delete the orphaned vector store + KB and re-run clean, or finish the DB rows manually.
|
|
280
|
+
- **Two prior KBs use the WRONG (fully-MANAGED) type.** `development-team-craftex` and
|
|
281
|
+
`development-team-toga-desk` were created by the earlier MANAGED code and were **intentionally
|
|
282
|
+
left as-is** (this session's scope was code-only). They should be **recreated later** to match
|
|
283
|
+
the canonical VECTOR + S3 Vectors design (dunn).
|
|
217
284
|
- **KB-list source differs per page.** The new `/talos/knowledge-bases` page lists from
|
|
218
285
|
`Team.KnowledgeBases` (`db_team`); `/talos/kb-documents` lists from live S3 folders. Don't
|
|
219
286
|
assume one reflects the other.
|
|
@@ -222,15 +289,27 @@ orphaned KB).
|
|
|
222
289
|
`Client_True.VectorIndexes` (Client cluster): `id, uuid`(UNIQUE)`, name, docSlug`(UNIQUE,
|
|
223
290
|
nullable)`, sectionSlug, chunkSlug, description` — create sets `docSlug=sectionSlug=chunkSlug=
|
|
224
291
|
bedrockKbId`.
|
|
225
|
-
- **
|
|
226
|
-
and reviewed, but the create flow has not been exercised in prod pending the `pdo_pgsql`
|
|
227
|
-
deploy plus network/IAM prerequisites (the developer is handling those).
|
|
292
|
+
- **Verified working end-to-end in production (2026-07-16)** with the VECTOR + S3 Vectors design.
|
|
228
293
|
- No new secret literals introduced; credentials live in the config sections above (documented by
|
|
229
294
|
section/account, never by value). AWS account id `654654170868`, bucket `togaiq`, and the KB
|
|
230
295
|
execution-role ARN are non-secret resource identifiers.
|
|
231
296
|
|
|
232
297
|
## Change history
|
|
233
298
|
|
|
299
|
+
- 2026-07-16 — **Corrected the KB-create architecture from MANAGED to VECTOR + S3 Vectors**
|
|
300
|
+
(the canonical design, from `development-team-dunn`; the earlier code was modeled on the WRONG
|
|
301
|
+
`craftex`/MANAGED KB). Rewrote `App_Talos_Bedrock`: KB is now `VECTOR` + `S3_VECTORS` storage;
|
|
302
|
+
added `s3VectorsClient()`, `vectorBucketName()`, and `createVectorStore()` (create vector
|
|
303
|
+
bucket + index sized to Titan v2, poll `getIndex` for the ARN); `createKnowledgeBase()` now
|
|
304
|
+
takes the index ARN; `createDataSource()` rewritten to plain `S3` + `BEDROCK_DATA_AUTOMATION`;
|
|
305
|
+
removed dead `BUCKET_NAME`/`BUCKET_OWNER_ACCOUNT_ID`. Wired a new **S3 Vectors provisioning
|
|
306
|
+
step** into `post.php` before KB creation (flow is now 9 steps) and added
|
|
307
|
+
`set_time_limit(CREATE_MAX_EXECUTION_SECONDS=600)`. **Decided on ONE shared IAM execution role**
|
|
308
|
+
(`…ForKnowledgeBase-talos`, hard-coded `ROLE_ARN`) instead of per-KB roles, to avoid granting
|
|
309
|
+
the app IAM write powers; granted the `[talos]` user (`bedrock-model-accessor`) the missing
|
|
310
|
+
`s3vectors` + `iam:PassRole` permissions (`s3vectors` is NOT in `AmazonBedrockFullAccess`).
|
|
311
|
+
**Verified working end-to-end in production.** `craftex` and `toga-desk` remain on the old
|
|
312
|
+
MANAGED type (left as-is; recreate later). (jcardinal)
|
|
234
313
|
- 2026-07-13 — Added the **`/talos/knowledge-bases` list + inline-rename page** (`get.php`;
|
|
235
314
|
lists from `Team.KnowledgeBases`, rename-only, no delete, existence-check before update),
|
|
236
315
|
registered first in the `talos-kb` nav group. Added the **`App_Pg`** tools-only PDO `pgsql`
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: architecture
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-16
|
|
10
10
|
owners: ["jcardinal", "rgirish", "mhammontree"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/_underscore.php
|
|
@@ -342,6 +342,7 @@ multi-file UI components (`.php`/`.html`/`.css`/`.js`) invoked as `<_ComponentNa
|
|
|
342
342
|
still refetches storage unconditionally, so a dirty read (read-after-assign, pre-save) discards the
|
|
343
343
|
unsaved value.
|
|
344
344
|
- **`_Database::register()` auto-starts a lazy transaction (since Apr 2 2026, commit `fa7835ed`).** Any code that calls `register()` and then writes to that DB must call `_Database::transactionCommit()` before the request ends — otherwise MySQL silently rolls back all writes when the connection closes. Lazy transactions only materialise on the first write, so read-only callers are unaffected. See `_underscore/Database.php:48`. First discovered when Rate SAML user provisioning silently discarded all new user INSERTs (Jun 2026).
|
|
345
|
+
- **PHP "Unclosed '{'" parse errors report a MISLEADING line number.** When a `.php` file loaded by the autoloader (`Loader.php`) has a dropped/unbalanced brace, PHP reports `Unclosed '{' on line N` where N is the **outermost `class X {` line** and fails at EOF — NOT at the true location of the missing `}`. Worse, because the file loads lazily via the SPL autoloader, the runtime trace points at the **caller** that triggered the autoload (e.g. a `new _Email()` call site), not the broken file. **Triage rule:** for an "Unclosed '{'" error, the real culprit is a missing `}` somewhere between the reported line and EOF of the file that failed to load — run `php -l <file>` (it reports the EOF line) and scan the whole file. **Merge-conflict resolutions are a common source of a single dropped brace** — review the entire merge, not just the one file the error appears to name. (First hit: production 500 EO-1, Jul 2026 — a `}` dropped from `_Email::send()` during merge `685e4a14` surfaced as a trace pointing at the `new _Email()` caller.)
|
|
345
346
|
|
|
346
347
|
## Change history
|
|
347
348
|
- 2026-06-11 — Documented lazy transaction gotcha in `_Database::register()` (rgirish)
|
|
@@ -349,3 +350,4 @@ multi-file UI components (`.php`/`.html`/`.css`/`.js`) invoked as `<_ComponentNa
|
|
|
349
350
|
- 2026-06-29 — Surface made the enforced (un-flagged) presentation path; reserved id blocks renumbered to Records 333–341 / RecordFields 2246–2433 (known seed-vs-provisioned drift). (jcardinal)
|
|
350
351
|
- 2026-07-02 — Fixed framework-wide `FIELD_STORAGE` write-drop and folder-read bugs in `Model.php`; noted the remaining unconditional-refetch dirty-read follow-up. (mhammontree)
|
|
351
352
|
- 2026-07-07 — Documented `_Query` writes-only async mode (`isAsync` → Worker `Infrastructure/Database/Query`) in the database-architecture section, linked `features/async-query-execution.md`, and noted the SQS-first `_Worker::runTask()` enqueue departure (caller does no MySQL; worker tier creates the row on pickup). (jcardinal)
|
|
353
|
+
- 2026-07-16 — Documented the misleading "Unclosed '{'" parse-error gotcha (autoloader reports the outermost `class {` line / caller trace, not the true dropped-brace location; merge conflicts a common cause). First hit production 500 EO-1 via a dropped `_Email::send()` brace. (jcardinal)
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
9
|
+
updated: 2026-07-16
|
|
10
10
|
owners: ["jcardinal", "bala", "mhammontree"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Client/EmailTemplate.php
|
|
@@ -106,6 +106,14 @@ can keep using `sendEmail($api, ...)`.
|
|
|
106
106
|
use ASCII-only content. Recommended **root-cause fix**: set `$mailer->CharSet = 'UTF-8'` in
|
|
107
107
|
`_Email::send()` — but that affects **every** client, so it should be a separate, tested
|
|
108
108
|
change rather than a drive-by edit.
|
|
109
|
+
- **⚠ SECURITY — live AWS SES SMTP credentials are hardcoded in `_underscore/Email.php`.**
|
|
110
|
+
The `SMTP_USERNAME` / `SMTP_PASSWORD` class constants (near the top of `_Email`) hold
|
|
111
|
+
**real** AWS SES SMTP credentials committed in source, violating the team no-secrets-in-code
|
|
112
|
+
rule (`rules/common/security.md`, `git-workflow.md`). Pre-existing (not introduced by the
|
|
113
|
+
Jul 2026 parse-error fix). **Remediation:** treat the committed values as compromised and
|
|
114
|
+
rotate them in AWS SES, then move them out of source into `Config/[environment].ini`
|
|
115
|
+
(read via `_Config`), matching how DB credentials are handled. Until then, be aware the
|
|
116
|
+
secret lives in the `_Email` constants — do **not** copy the values anywhere.
|
|
109
117
|
- **`clientIdentifier` does NOT pick the template DB.** `_Email::send()` uses
|
|
110
118
|
`clientIdentifier` only for CloudWatch logging/validation. The template loads from whatever
|
|
111
119
|
DB the `DB_CLIENT` alias points at — so register the right `Client_<x>` schema before
|
|
@@ -130,6 +138,11 @@ worker method) in-process instead.
|
|
|
130
138
|
|
|
131
139
|
## Change history
|
|
132
140
|
|
|
141
|
+
- 2026-07-16 — Recorded the **hardcoded AWS SES SMTP credentials** security gotcha in
|
|
142
|
+
`_Email` (`SMTP_USERNAME`/`SMTP_PASSWORD` constants; pre-existing — rotate + move to
|
|
143
|
+
`Config`). Surfaced while fixing a production 500 (EO-1) whose root cause was a single
|
|
144
|
+
`}` dropped from `_Email::send()`'s header `foreach` during merge `685e4a14`; the fix
|
|
145
|
+
restored the brace (`php -l` clean). (jcardinal)
|
|
133
146
|
- 2026-06-30 — Documented the **`CharSet=UTF-8` mojibake gotcha** (`_Email::send()` doesn't
|
|
134
147
|
set it → non-ASCII content garbles; scoped workaround = ASCII-only, root-cause = set
|
|
135
148
|
`$mailer->CharSet` as a separate tested change), clarified that `clientIdentifier` does not
|
package/package.json
CHANGED