Agent tool hardening: annotation fields corrected, citations resolve real UUIDs, errors surface messages

Eight commits tighten the document-edit tool family: missing DB columns are populated, generate_docx download cards are fixed, citations are rewritten to carry real document UUIDs rather than chat-local labels like "doc-0", and tool errors now return the actual error message rather than a generic string.

draftingworkflow

The edit_document tool had been INSERTing into document_edits without change_id, del_w_id, or ins_w_id. Those come from the applyTrackedEdits return value - specifically appliedChanges[i].id, .delId, and .insId. efb0290 wires that return value and adds context_before and context_after to the INSERT. The annotation payload sent in the SSE stream now also carries status: 'pending', which EditCard in the frontend requires to render correctly.

The download URL from edit_document was a presigned S3 URL (15-min TTL). 3f61433 changes it to a backend-relative path /single-documents/{docId}/docx?version_id={versionId}, which is more stable and routes through the existing auth middleware.

generate_docx had a DB INSERT using source: 'assistant_generated' against a column that only accepts 'generated', silently failing. 0cbbf5e fixes the value and also adds a doc_created_start SSE event with a sanitized filename so the streaming tool spinner shows something useful.

The citation UUID rewrite (c85201f) is the structural change. The extractAnnotations parser is updated to expect document_id (a real UUID) rather than doc_id (a chat-local label). The agent's system prompt instructs it to output UUIDs sourced from list_documents output. A UUID regex validates each citation and drops malformed ones. A tail-buffer is added to the SSE stream to suppress the <CITATIONS> block from reaching the frontend as visible text.

A logger.ts helper adding logInfo/logError functions that emit structured JSON lands across all tools, giving CloudWatch a consistent shape to query.

So what The UUID citation approach (`c85201f`) is worth importing if you are building on the same pattern - raw position labels are brittle across sessions. The structured JSON error logging convention is the right shape to build on. The annotation field and INSERT fixes are schema-specific to this fork; treat them as test cases, not imports.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

8 commits from dropthejase/louis, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
efb0290f fix(agent): populate change_id, del_id, ins_id in document_edits INSERT Jason Lee 2026-05-12 ↗ GitHub
a1cef7a5 feat(agents): add structured JSON error logging to all tools Jason Lee 2026-05-12 ↗ GitHub
Add logger.ts helper to both main and tabular agents. Wraps console.log/error
with JSON output (level, tool, message, error, stack). All tool callbacks now
catch exceptions and log full stack traces to CloudWatch via stderr.
3f614333 fix: annotation status field and download URL in edit_document tool Jason Lee 2026-05-12 ↗ GitHub
commit body
- Add status: 'pending' to annotation payload so EditCard does not
  immediately resolve and disable Accept/Reject/View buttons
- Replace presigned S3 URL with backend-relative path for download_url
  so DocDownloadBlock isSafeHref check passes
- Remove unused getPresignedUrl import
- Add TEMP_TASKS.md to .gitignore
- Note tool spinner parity item in FEATURE-PARITY.md
0cbbf5ed fix(agents,frontend): fix generate_docx download card not showing Jason Lee 2026-05-13 ↗ GitHub
commit body
- Fix source constraint: 'assistant_generated' -> 'generated' to match
  document_versions_source_check constraint
- Fix doc_created_start filename mismatch: sanitize title to match the
  filename the tool returns so frontend updateMatchingEvent finds a match
- Fix DocDownloadBlock: open presigned S3 URLs directly instead of
  rejecting them via isSafeHref check
c85201fd fix(citations): resolve document UUIDs in agent citations end-to-end Jason Lee 2026-05-13 ↗ GitHub
commit body
- Agent outputs real document_id/version_id UUIDs in <CITATIONS> block sourced from <document_metadata> appended to read_document output
- DocStore extended with document_id + version_id so read_document can append metadata
- extractAnnotations parses document_id directly, validates UUID format, cross-checks against known doc set, drops and warns invalid entries
- <CITATIONS> block suppressed from SSE stream - never shown in chat UI
- History reload extractCitationsFromText validates UUID format on parse
- System prompt updated: citations use document_id/version_id/filename fields; doc-N labels banned from <CITATIONS>
833bb5d3 fix(agents): surface err.message in tool error returns Jason Lee 2026-05-13 ↗ GitHub
c05081b4 fix(agent): use source doc filename for doc_replicated SSE to match doc_replicate_start Jason Lee 2026-05-13 ↗ GitHub
b06b54ef fix(agent): wire workflow marker and attached documents to AgentCore Jason Lee 2026-05-15 ↗ GitHub
commit body
Three bugs prevented workflows and doc selection from working:
1. useAssistantChat never prepended [Workflow: title (id)] marker to prompt
2. DisplayWorkflowModal never set workflow field on the outgoing message
3. agents/index.ts never read attached_documents from request body

Agent system prompt + read_workflow/list_workflows tools were already
correct - only the triggers were missing.

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-347.md from inside the repo you want the changes in.

⬇ Download capture-thread-347.md