Skip to content

Release/1.7.0#671

Merged
philmerrell merged 1655 commits into
mainfrom
release/1.7.0
Jul 17, 2026
Merged

Release/1.7.0#671
philmerrell merged 1655 commits into
mainfrom
release/1.7.0

Conversation

@philmerrell

Copy link
Copy Markdown
Contributor

Release 1.7.0

Feature release (minor bump 1.6.11.7.0).

🚀 Added

  • Word (.docx) document toolsetcreate_word_document, modify_word_document, list_word_documents, read_word_document, each running python-docx in a Bedrock Code Interpreter session and persisting to the user-files store, with an inline word_document renderer + download button. Behind the create_word_document capability toggle; seeded into bootstrap DEFAULT_TOOLS (Add Word document tools (create/modify/list/read) #670)

✨ Improved

🐛 Fixed

🏗️ Infrastructure

📦 Dependencies

Deployment

🏗️ CDK deploy required for the new SessionRecencyIndex GSI (platform.yml before backend.yml). The Phase 1a reader degrades gracefully if the GSI is absent, so deploy order is not load-bearing. No data migration, no breaking changes. Word toolset is dark until an admin enables create_word_document.

See RELEASE_NOTES.md and CHANGELOG.md for full detail.

🤖 Generated with Claude Code

philmerrell and others added 30 commits July 3, 2026 23:05
…ted-turn-metadata

feat(interrupted-turn): persist stopped-turn metadata so cost + message badges survive
The KB sync worker resolves the policy creator's Google token from the
AgentCore Identity vault via GetResourceOauth2Token, but that call reads
the refresh token *through* the Secrets Manager secret the vault
auto-creates per provider (bedrock-agentcore-identity!default/oauth2/<id>).
The worker role granted only the two bedrock-agentcore:* actions, so the
call failed with AccessDenied on secretsmanager:GetSecretValue and every
Drive sync returned "failed".

Add the read-only AgentCoreIdentityOAuthSecrets grant (GetSecretValue +
DescribeSecret on ...!default/oauth2/*) — the same grant app-api and
inference-api already carry, minus the write lifecycle a background
fetcher never needs. Covered by a new assertion in kb-sync.test.ts.

Verified live in dev-ai: with the grant, the worker gets past the vault
read (the remaining paused_reauth is a genuine expired-refresh-token,
not this IAM gap).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…er-vault-secret-read

fix(kb-sync): grant worker read on the vault's backing OAuth secrets
…r baseline

`custom_parameters_for` previously injected vendor-specific OAuth params
(Google `access_type=offline`, plus `prompt=consent` on the force-auth
path) on top of the connector's admin-configured extras, keyed off
`provider_type`. That hid a documented requirement inside the code and
made the `customParameters` map depend on the call site (grant vs
retrieval), which AgentCore factors into its vault key.

Simplify to a single rule: every call site forwards the connector's
admin-configured `customParameters` verbatim via
`custom_parameters_for(admin_extras)`. Admins set `access_type=offline`
and `prompt=consent` in the connector's "Custom OAuth Parameters" field
(the seeded Google connector already carries both), so the same map is
sent on consent and on every retrieval — no baseline merge, no
`provider_type`/`force_authentication` branching, no per-call-site drift.

Removes `_vendor_baseline_params`, the `provider_type_lookup` plumbing on
the consent hook, and the `force_authentication=True` customParameters
argument at all read sites (the SDK-level `force_authentication` flag is
unchanged). Behaviour for the existing Google connector is identical
(same resulting map); the win is that the vault key is now provably
consistent and there are no hidden customizations in the token path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two design specs drafted alongside recent exploration work:
- tool-search-token-bloat-strategy: cross-source tool-search plan for
  MCP token bloat (tiered discovery, AWS Agent Registry tier).
- user-markdown-memory: per-user markdown "second brain" memory,
  re-scoped skills reference-file mechanism, prompt-cache injection.

Docs only; no code or behaviour change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…dmin-configured-custom-params

refactor(oauth): forward admin customParameters, drop hardcoded vendor baseline
…-and-user-memory-specs

docs: add tool-search token-bloat + per-user markdown memory specs
A reauth pause was opaque — "credentials need re-consent" gave no hint
why. The vault token is keyed by (workload identity, userId), so the
overwhelmingly common cause is that the token was vaulted under a
DIFFERENT workload identity than the worker queries: e.g. a consent done
through local dev (AGENTCORE_RUNTIME_WORKLOAD_NAME=local_dev_inference)
can't be read by the deployed worker (platform-workload), and vice
versa. That exact mismatch cost hours to diagnose.

Surface the workload name, userId, and provider the lookup used in the
pause warning so the mismatch is obvious in one log line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…reauth-diagnostics

feat(kb-sync): log workload identity + userId on a reauth pause
KB sync ships dark: the EventBridge rule is created disabled and the
KB_SYNC_ENABLED kill switch is false unless CDK synths with
CDK_KB_SYNC_ENABLED=true (config.ts). platform.yml never forwarded that
var, so a CDK deploy always synthed the feature off — the only way to
enable it was an out-of-band CLI flip that reverts on the next deploy.

Forward it as an environment-scoped `${{ vars.CDK_KB_SYNC_ENABLED }}`
like every other CDK_ var. The development environment variable is set
to "true" (enables the rule + kill switch in dev-ai durably); production
leaves it unset, so it stays dark until validated there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…able-dev

chore(kb-sync): plumb CDK_KB_SYNC_ENABLED into the platform deploy
KB sync shipped opt-in (default off), a holdover from ship-dark
incremental development. The feature is complete and guarded, so a
deployer/cloner of the public stack should get it working by default —
a hidden default-off flag is bad DX. Invert to opt-out: enabled unless
CDK_KB_SYNC_ENABLED=false (or a `kbSync.enabled: false` cdk.json context).

The workflow forwards `${{ vars.CDK_KB_SYNC_ENABLED }}`, which is an empty
string when unset — a plain `?? false` fallback wouldn't flip the default,
so config.ts treats empty/unset as "use the default (on)" and only the
literal "false" as the kill switch. Adds config-resolution tests covering
unset / empty / "true" / "false" / context-disable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…fault-on

chore(kb-sync): default the feature ON with a kill switch
The knowledge-base sync control was a bare "Manual only" dropdown that
never explained what syncing does, and its status line only appeared
while a schedule was active — a manual-only file showed nothing.

- Lead the control with an "Auto-sync from <source>" label (with a
  descriptive title tooltip) so every row states what it is and where it
  pulls from.
- Rename the options to self-describing verbs: "Don't auto-sync",
  "Sync daily/weekly/monthly".
- Always surface a "Last synced" line, including manual-only sources, via
  a new lastSyncedAt input fed from Document.lastSyncedAt.
- Pair a relative age with an absolute date/time ("Synced 2h ago ·
  Jul 3, 2:14 PM") for both "how long ago" and "exactly when".

Display-only; the timestamps already exist in the data model.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Aligns the knowledge-base sync control with the approved mockup and fixes
a bug that rendered the status line as a bare "Synced · next sync".

Layout:
- Move the "Auto-sync from <source>" context out of the control's button
  row (where it forced "Pause" to wrap) and into the file's meta line.
- Compact the control to just the schedule select + actions.
- Add a status-line dot (green healthy / amber attention / grey idle).
- Top-align the status icon and download/trash actions with the filename
  (items-start) instead of floating against the taller row.

Timestamp bug: several generators built ISO strings as
`datetime.isoformat() + "Z"`, yielding "…+00:00Z" (offset AND Z). That is
invalid ISO 8601 and parses to Invalid Date in strict engines (Safari),
so last-sync / next-sync rendered blank. Normalize to a single trailing Z
in service, dispatcher, and worker; harden the dispatcher parser to always
return a UTC-aware datetime; and harden the SPA to tolerate the legacy
"+00:00Z" so already-persisted policies still render.

Download and delete controls on documents are preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The web-source (crawl) row shared the sync control with documents but was
missing the parity bindings the document row got: no source-context line
and no persistent last-synced timestamp, so a manual web source rendered
as a bare dropdown while an identical document showed full context.

- Add the meta-line context "Auto-sync from the web" (guarded by
  isCrawlSyncable), mirroring the document's "Auto-sync from <provider>".
- Feed the control lastSyncedAt from crawl.completedAt so a manual web
  source still shows when it last refreshed (the component already prefers
  the policy's lastSyncAt when a schedule is active).
- Make the crawl meta line wrap-safe (flex-wrap), matching the doc row.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Web sources list had no loading flag, so it popped into existence
after its network round-trip, while Uploaded Documents showed a lone
centered spinner — two async lists with inconsistent, jarring loads.

Introduce one initial-load gate for both lists:
- Add isLoadingCrawls, set from loadSyncData (cleared on the viewer
  early-return and in finally), mirroring isLoadingDocuments.
- isLoadingKnowledge computed gates both lists so they reveal together;
  raise both flags synchronously in ngOnInit so the first paint is the
  skeleton, not an empty flash.
- Replace the documents spinner with a skeleton list (pulsing icon + two
  text bars, varied widths) that mirrors the final row shape — no layout
  shift, and consistent with the existing connector-button skeleton.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Changing the schedule (e.g. Don't auto-sync → Sync weekly) held the busy
state for the whole create/update/delete round-trip but only disabled the
controls — there was no positive sign anything was happening, and the
select eagerly reverts to its old value until the mutation confirms, so it
read as "nothing happened".

While busy, the status slot now shows a spinner + "Saving…" (role=status),
taking precedence over the sync status line — including for a manual-only
source being enabled, where no policy or status exists yet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…status-clarity

fix(kb-sync): clarify the auto-sync control and repair blank sync timestamps
UserSyncService built timestamps as `datetime.isoformat() + "Z"`, yielding
"…+00:00Z" — both an offset AND a Z. That is invalid ISO 8601 and parses to
Invalid Date in strict engines (Safari), so the admin user-list "Last login"
and user-detail "Created"/"Last login" dates (rendered via `new Date()`)
showed "Never".

Same class of bug just fixed across KB-sync (service/dispatcher/worker);
this applies the identical normalization to the users domain.

- Write path: add `_iso()` helper, normalize `created_at`/`last_login_at`.
- Read path: add `_heal_iso()` and apply in `_item_to_profile` /
  `_item_to_list_item` so legacy "+00:00Z" rows render correctly. Necessary
  because `created_at` is preserved across logins forever (never rewritten),
  so pre-fix users would otherwise show "Never" in Safari permanently.
- Regression tests for the write-path invariant and read-path heal.

`last_login_at` also backs GSI2SK/GSI3SK (sort-by-last-login); the suffix
change is lexicographically safe — ordering is dominated by the microsecond
datetime prefix and a transient mix of "+00:00Z"/"Z" rows does not corrupt it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…mestamp-zulu

fix(users): normalize sync timestamps to strict ISO 8601 (single Z)
…panel

Wrap the Knowledge base section on the Assistant editor in a rounded,
bordered inset with a subtle gray-100/60 fill instead of the flat
border-t divider shared by other sections. Against the gray-50 form
column this reads as a mildly contrasted group, and the white inner
lists (Web sources / Uploaded Documents) now float on the tint to
reinforce the grouping. Drops the border-t/pt-8 divider since the card
provides its own separation; the form's space-y-8 preserves the top gap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add Drive, Docs, Gmail, and Calendar icon assets under public/logos.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add Google connector logo SVGs (Drive, Docs, Gmail, Calendar).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… + spike brief

Reframe the proactive-agent effort from a single "Oliver" feature into a
primitive-enablement plan, mapped onto the Harness (headless run entrypoint)
and Registry (catalog + governance) explorations.

- agentic-platform-primitives.md: primitive maturity + gap ledger, the six
  fundamentals (F1 headless run entrypoint .. F6 registry/governance),
  phased plan, and Harness/Registry overlap. Oliver demoted to one
  validation use case among several.
- scheduled-agent-runs.md: detailed design for F1+F2+F3 (renamed from the
  earlier Oliver draft; generalized so any config/prompt/cadence works).
- harness-entrypoint-spike-brief.md: tight spike brief for the F1 keystone
  (unattended-as-user auth + server-side SSE), to run in dev-ai.

Resolved decisions: F1 = minimal internal run_agent_headless(), A2A-ready;
governance floor (F6a) pulled forward into Phase A, Registry discovery (F6b)
deferred. Open: KB decoupling appetite, floor depth, sequencing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…primitives-plan

docs(specs): agentic platform primitives plan (+ scheduled-runs design + F1 spike brief)
…ev-ai

run_agent_headless in apis/shared/harness: per-owner Cognito bearer mint
(workload-token + SigV4 front-door paths proven dead at the runtime
gateway), server-side SSE drain pinned to live wire shapes, F6a audit
records + guardrails/classification seams, delivery via the runtime's own
session materialization + title override. Driver script reproduces the
dev-ai proof and the negative auth probes. Findings + Phase A design in
docs/specs/harness-entrypoint-spike-findings.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The headless-run entrypoint spike (Fable 5) is GO — proven end-to-end in
dev-ai. Bring its findings doc onto develop as the decision record and lock
the four gate decisions into the plan of record.

- Add harness-entrypoint-spike-findings.md (design deliverables + Phase A
  punch list; full spike code lives on branch spike/harness-headless-entrypoint).
- agentic-platform-primitives.md §6: resolve act-as-user auth policy (Cognito
  per-owner token behind an explicit headless-grant record), F6a floor depth
  (audit fail-closed now; PII checkpoint required before unattended schedules),
  KB decoupling (defer), sequencing (proactive-spine-first confirmed).
- scheduled-agent-runs.md §8: mark unattended-auth resolved with the chosen path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… primitive

Replace the spike's BFF-table Scan with an explicit headless-grant record
(apis/shared/harness/grants.py): create-on-enable from an attended session,
per-owner lookup via the sparse HeadlessGrantUserIndex GSI, revocation that
deletes the stored credential, and a documented "must have logged in within
30 days" policy (TTL anchored to the login that issued the pinned refresh
token, matching the Cognito refresh-token validity).

CognitoRefreshBearerAuth now mints from the grant (rotation-aware: a rotated
refresh token is persisted back before the mint returns — punch-list #5).
Dedupe build_invocations_url into the harness as the single canonical
resolver; the chat proxy imports it (punch-list #4). Document the
enabled_tools=None = all-RBAC-allowed semantic and the schedule-snapshot
rule (punch-list #7). Governance docstrings updated to the locked F6a
decision: audit-only fail-closed + wired no-op guardrail/classification
seams, implementations gated to the scheduled phase. Add an
_build_http_client seam and tests covering the grant lifecycle,
grant-backed minting, audit fail-closed ordering, and stream outcomes
against a MockTransport runtime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lity

POST /runs/now executes one agent turn through the exact unattended path a
scheduled run will use (create-on-enable grant -> per-owner Cognito mint ->
runtime /invocations -> server-side SSE drain -> governance floor -> session
materialization) — the PR-1 validation surface from
docs/specs/scheduled-agent-runs.md §7. GET/DELETE /runs/grant expose grant
status and total revocation.

Gating is two independent controls (spec §6): the SCHEDULED_RUNS_ENABLED
kill switch (default ON; only the literal "false" disables — empty workflow
vars can't dark-stop prod) and a new `scheduled-runs` RBAC capability
resolved through the mature tools grant axis
(apis/shared/rbac/capabilities.py) — GA = grant the id to the default role.
Auth is the standard SPA cookie dependency per the CLAUDE.md app-api rule;
mint failures surface as 409, never 401, so the SPA is not bounced through
the login redirect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
philmerrell and others added 26 commits July 15, 2026 13:31
…ed-conversations-iam-grant

fix(infra): grant app-api task role access to shared-conversations table
Sharing a large conversation failed: ShareService.create_share inlined the
full message list into a single DynamoDB item, exceeding the 400 KB item
limit and surfacing to users as a bare 500 (observed in prod-ai as a PutItem
ValidationException). This is separate from the IAM-grant bug in PR #657.

Offload the snapshot body (messages + metadata) to a new private
shared-conversations S3 bucket, keeping only control fields plus a body_ref
pointer in DynamoDB — mirroring the Memory Spaces / Artifacts / Skills
S3-offload pattern. Reads fall back to inline for legacy shares, so existing
shares keep working with no migration and the SPA contract is unchanged.

- New ShareSnapshotStore (content-addressed S3 put/get/delete, SSE-S3, dedupe)
- create_share writes body to S3 + body_ref item; revoke/session-cleanup
  best-effort delete the object
- _load_snapshot_body reads from S3 or falls back to legacy inline items
- ShareStorageUnavailableError -> friendly 503 instead of a bare 500
- CDK: shared-conversations bucket + SSM param, compute-ref, app-api env
  (SHARED_CONVERSATIONS_BUCKET_NAME), and SharedConversationsBucketReadWrite
  IAM grant (app-api only)
- Tests: store round-trip/dedupe, >400 KB regression, S3 + legacy reads,
  export-from-S3, revoke cleanup, storage-unavailable

Spec: docs/specs/share-large-conversations-s3-offload.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rge-conversations-s3-offload

feat(shares): offload large-conversation snapshots to S3
…evelop-1.6.0

# Conflicts:
#	backend/src/agents/main_agent/session/tests/test_history_repair.py
#	backend/src/apis/inference_api/chat/routes.py
…nto-develop-1.6.0

Backmerge: main → develop (1.6.0)
Agent (assistant) model bindings persist only `model_id` — never
`provider` — so previewing/invoking an agent bound to a Mantle model
(e.g. `openai.gpt-5.4`) resolved to provider=None. That misroutes the
model to Bedrock ConverseStream, which rejects it with "The provided
model identifier is invalid", even though the same model works from the
normal chat path (which always sends `provider` alongside `model_id`).

Two complementary fixes:

- Backend (server-authoritative): `_resolve_model_settings` now also
  returns the model's registered `provider` from the managed-model
  registry, and the invocation path backfills `effective_provider` from
  it when the request/binding didn't carry one. This fixes all existing
  agents with a provider-less stored binding — no data backfill needed —
  and mirrors how `mantle_api_mode`/`mantle_region` are already recovered.
  The app-tool-call / app-context-update rebuild paths get the same
  fallback so a rebuilt agent keys on the same provider as its main turn.

- Frontend: the Agent Designer save payload now persists the selected
  model's `provider` (from the catalog `meta.provider`) alongside
  `modelId`, so newly created/edited bindings are self-describing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resume turns (interrupt_responses set — OAuth-gated MCP consent or
tool-approval) crashed with `NameError: cannot access free variable
'effective_enabled_tools'`. The variable is referenced unconditionally by
the `stream_with_quota_warning` streaming closure (attachment guidance +
tabular inventory) but was only assigned in the non-resume branch. On
resume the closure raised before its first yield, the inference-api
container returned 500, and the AgentCore Runtime data plane translated
that into a 424 Failed Dependency to app-api and the SPA.

This broke every interrupt-resume turn since the agent-designer
tool-binding refactor (0b9b039) — most visibly "connect to Gmail for
employees", which completes via an OAuth-consent resume. Bind
effective_enabled_tools from the paused-turn snapshot on the resume
branch (the same source the resume get_agent call uses).

Adds a resume-path regression test to tests/routes/test_inference.py that
drives /invocations with interrupt_responses and asserts a 200 stream;
without the fix it fails with the NameError.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…er-resolution

fix(agents): resolve model provider for agent-bound invocations
…tive-enabled-tools-nameerror

fix(inference): bind effective_enabled_tools on resume path (prod 424 on OAuth-gated MCP connect)
…nto-develop-1.6.1

Backmerge: main into develop (1.6.1)
…2026-07-10

chore(kaizen): weekly research scan 2026-07-10
Generated by the kaizen-research skill. Top 5 ideas appended to
docs/kaizen/review-queue.md for the kaizen-review-prep run later this morning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Root-cause spec for the SessionMetadata parse-failure warnings: the session
row's sort key encodes lastMessageAt, forcing a delete+put row move every turn.
Concurrent writers race that move and upsert bare ghost rows. Also drives the
first-turn duplicate-row race.

Fix: static SK (S#{session_id}) + sparse SessionRecencyIndex GSI for recency
listing. Covers the expand -> migrate -> backfill -> contract migration,
downstream/forked-deployment safety (marker gate + graceful GSI-missing
fallback), pagination-token compatibility, and the test matrix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…175 Phase 0)

Sparse recency index (GSI4_PK=USER#{id}, GSI4_SK={lastMessageAt}#{session_id},
projection ALL) for newest-first active-session listing once the base sort key
becomes static. Phase 0 of the static-sort-key migration: adding the index is a
no-op until rows populate GSI4 keys, so it deploys safely ahead of any code
change. IAM already covers it via the SessionsMetadataAccess /index/* wildcard.

Update tables-detailed test to assert all four GSIs (the "2 GSIs" title was
already stale after DueScheduleIndex) and the new index's key schema.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…metadata-static-sk-phase0

feat(infra): SessionRecencyIndex GSI on sessions-metadata (issue #175 Phase 0)
…Phase 1a)

Expand-read step of the static-sort-key migration. list_user_sessions now reads
the UNION of two disjoint sources so a session is visible whether or not its base
sort key has been migrated to the static S#{session_id} form:

- legacy (un-migrated): base table, SK begins_with 'S#ACTIVE#'
- migrated: SessionRecencyIndex GSI (GSI4_PK=USER#{id}, GSI4_SK={lastMessageAt}#{id})

Pagination switches to a value cursor ({lastMessageAt}#{session_id}) so each page
is derived independently from the last returned position, with no cross-page
buffering; fetching limit+1 valid rows per source is provably enough to detect a
next page. The cursor decoder is tolerant — legacy/undecodable tokens fall back to
first page (a harmless reset across the deploy boundary).

Degrades to legacy-only if SessionRecencyIndex doesn't exist yet (code ahead of the
CDK GSI): the GSI query's ResourceNotFoundException is caught.

No writes change and no row migrates in this phase — this only teaches every reader
to cope with both schemes, which must be fully rolled out before Phase 1b turns on
self-migrating writes.

Tests: union ordering, cross-union pagination (no dupes/gaps), migrated-only via
GSI, ghost/preview skip, and graceful fallback when the index is absent. conftest
sessions_metadata_table fixture gains the SessionRecencyIndex GSI to match prod.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…metadata-static-sk-phase1a

feat(sessions): dual-scheme union read for session listing (issue #175 Phase 1a)
Auto prompt caching (CacheConfig strategy=auto) appended its cachePoint
after the last user message's content, so any turn attaching a non-PDF
document (txt/docx/csv/...) sent [text, document, cachePoint] and
Bedrock's Anthropic adapter rejected it with "ValidationException ...
messages.N.content.M.type: Field required", surfacing to users as
"Agent force-stopped" (prod incidents Jul 14-16, e.g. session
dd1a647a on a .txt transcript upload).

strands 1.48.0 places the cache point before the first non-PDF document
block instead (upstream issue #1966); every placement it produces was
verified live against global.anthropic.claude-sonnet-4-6 ConverseStream.
Also corrects the model_config comment that credited PR #1438/1.39.0
with this fix - #1438 was the auto-caching feature itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ce-stop-validation-791e6f

fix(deps): bump strands-agents to 1.48.0 for cachePoint-attachment fix
…2026-07-17

chore(kaizen): weekly research scan 2026-07-17
… missing GSI (issue #175)

The Phase 1a dual-scheme read (PR #667) catches a missing SessionRecencyIndex to
fall back to legacy-only listing, but only handled ResourceNotFoundException — what
moto raises. Real DynamoDB raises ValidationException ("The table does not have the
specified index") for a missing GSI (verified against the prod table). So if the
1a backend deployed to an environment before the CDK GSI existed, list_user_sessions
would 503 instead of degrading.

Broaden the catch to also handle ValidationException (scoped by the "specified index"
message so genuinely malformed queries still surface). This restores the intended
order-independence: 1a is safe whether or not SessionRecencyIndex exists yet, which
matters for prod deploy ordering (backend.yml vs platform.yml) and for forked
deployments.

Add a test that reproduces the real ValidationException on the index query (moto
masks it), asserting fallback to legacy-only results.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Provision a full Word (.docx) toolset behind the single create_word_document capability toggle. Each tool runs python-docx in Bedrock Code Interpreter and uses the existing user-files store (S3 + DynamoDB) for persistence and delivery. - create/modify/list/read tools in agents/builtin_tools/word_document_tool.py, injected per-request via _build_word_document_tools (inference_api/chat/routes.py). - Frontend inline-visual 'word_document' renderer with an accessible download button (Tailwind utilities, no scoped CSS). - Restore-time content-block sanitizer in TurnBasedSessionManager: drops empty/typeless blocks from restored history that caused Bedrock ConverseStream 'messages.N.content.M.type: Field required'. - Seed create_word_document in bootstrap DEFAULT_TOOLS ('Word Documents') + updated seed tests.
…ument-tools

Add Word document tools (create/modify/list/read)
…-missing-index-fallback

fix(sessions): degrade to legacy-only on real ValidationException for missing GSI (issue #175)
Feature release: Word (.docx) document toolset for the agent plus the read-side phases of the session-metadata static-sort-key migration (issue #175).

- Add create/modify/list/read Word document tools (python-docx in Code Interpreter, user-files store) behind the create_word_document toggle, with an inline word_document renderer + download button (#670)
- Session listing dual-scheme union read across legacy + SessionRecencyIndex, value-cursor pagination (issue #175 Phase 1a) (#667)
- New sparse SessionRecencyIndex GSI on sessions-metadata (issue #175 Phase 0) (#666)
- Degrade session listing to legacy-only on ValidationException for a missing GSI (#669)
- Bump strands-agents to 1.48.0 to fix cachePoint-after-attachment 'Agent force-stopped' on non-PDF uploads (#668)
- Restore-time content-block sanitizer in TurnBasedSessionManager (#670)

Bump VERSION 1.6.1 -> 1.7.0 and sync manifests + lockfiles.
@philmerrell
philmerrell requested a review from a team July 17, 2026 20:05
@philmerrell
philmerrell merged commit f885863 into main Jul 17, 2026
11 checks passed
@philmerrell
philmerrell deleted the release/1.7.0 branch July 17, 2026 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants