Strands agent with 10 tools built on AgentCore Runtime; JWT userId extraction added
dropthejase built the AI chat core as a TypeScript Strands agent running on AWS AgentCore Runtime - replacing upstream's inline LLM loop with a proper tool-dispatching agent that handles document reads, edits, generation, workflow access, and per-user credits tracking. The tool definitions are largely reusable independent of Strands.
The agents/ workspace scaffolds a Strands SDK agent with 10 tools across three groups. Document read tools: read_document, find_in_document, list_documents, fetch_documents. Document write tools: generate_docx (structured section/table schema), edit_document (tracked-change edits via applyTrackedEdits), replicate_document. Metadata tools: list_workflows, read_workflow, plus a read_table_cells that is later removed because review_id can't be supplied to the main agent.
Shared libs cover secrets (Secrets Manager cold-start cache), storage (S3 get/put/presign), and a citations.ts parser. Doc context is built per-turn: buildDocContext for standalone documents, buildProjectDocContext for project-scoped sessions. The agent factory instantiates a BedrockModel with cross-region inference profile IDs (e.g. eu.anthropic.claude-sonnet-4-6-20250922-v1:0 for eu-west-1) and assembles tools from the factory functions.
A later commit (7024448) stops trusting userId from the request body and instead extracts it from the Bearer JWT sub claim at the HTTP layer before any agent code runs. The same commit removes the backend's chat_messages write - persistence ownership moves to the agent side.
Subsequent iterations migrate from Supabase to Aurora RDS Data API, add a AfterModelCallEvent hook that increments per-user DynamoDB credits, and create a dedicated AgentCore execution IAM role with CloudWatch Logs, X-Ray, and scoped Bedrock permissions.
The tool factory pattern (each tool returned by a make*Tool(deps) function rather than defined at module scope) is what makes the tools testable in isolation. The citations.ts lib is also clean enough to reuse without the rest of the agent.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?