#15148: auto-reply: add message_time and compact inbound metadata JSON
size: S
## Summary
This patch improves prompt context reliability and token efficiency for structured inbound metadata:
1. Add `message_time` to `Conversation info (untrusted metadata)` so the model can see the current inbound message time in areadable, timezone-aware format.
2. Reuse envelope timestamp formatting logic for consistent timezone handling.
3. Compact JSON output for inbound metadata blocks to reduce prompt token usage.
## Problem
During the prompt-shaping migration from legacy envelope lines to structured metadata blocks, the current-message timestamp was not carried over into inbound metadata.
As a result, the model can lose explicit time context for the latest user turn even when `ctx.Timestamp` is available.
## Before / After
Before migration (legacy envelope format, timestamp present):
```text
[Telegram [User] id:123456 +5s Fri 2026-02-10 10:23 GMT+8]
```
After migration (structured metadata, current-message timestamp missing):
Conversation info (untrusted metadata):
```json
{
"conversation_label": "[User] id:123456"
}
```
After this patch (structured metadata + readable current-message time):
Conversation info (untrusted metadata):
```json
{"conversation_label":"[User] id:123456","message_time":"Fri 2026-02-10 10:23 GMT+8"}
```
Also in this patch, metadata JSON formatting is compacted (single-line JSON) to reduce prompt token usage.
## What Changed
- `src/auto-reply/reply/inbound-meta.ts`
- Added optional envelope-format options to `buildInboundUserContextPrefix(...)`.
- Added `message_time` into `Conversation info (untrusted metadata)` when `ctx.Timestamp` is available.
- Switched all inbound metadata JSON rendering from pretty (`JSON.stringify(..., null, 2)`) to compact (`JSON.stringify(...)`).
- `src/auto-reply/reply/get-reply-run.ts`
- Pass envelope formatting config (`resolveEnvelopeFormatOptions(cfg)`) into `buildInboundUserContextPrefix(...)`.
- `src/auto-reply/envelope.ts`
- Exported timestamp formatter as `formatEnvelopeTimestamp(...)` for shared use.
- Tests
- Added `src/auto-reply/reply/inbound-meta.test.ts`.
- Updated `src/auto-reply/reply.raw-body.test.ts` assertions for compact JSON output.
## Behavior Notes
- `message_time` is sourced from `ctx.Timestamp` only.
- `message_time` respects envelope timestamp visibility config (`agents.defaults.envelopeTimestamp`), i.e. it is omitted when timestamp output is disabled.
- No message interval field is added.
## AI-Assisted Transparency (Vibe-Coded)
- AI-assisted: **Yes** (Codex, gpt-5.3-codex high).
- Testing degree: **Fully tested** (`pnpm test` full suite passed).
- Deployment validation: **Passed** in personal production deployment.
- Author understanding: I reviewed and understand the implemented changes and their runtime behavior.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates auto-reply prompt shaping to (1) include the current inbound message timestamp in the user-role “Conversation info (untrusted metadata)” block as `message_time`, formatted using the same envelope timestamp logic and honoring `agents.defaults.envelopeTimestamp`, and (2) compact JSON rendering for inbound metadata blocks (switching from pretty-printed `JSON.stringify(..., null, 2)` to compact `JSON.stringify(...)`) to reduce prompt token usage.
Changes are localized to the auto-reply prompt construction pipeline: `formatEnvelopeTimestamp` is exported from `src/auto-reply/envelope.ts` and reused by `src/auto-reply/reply/inbound-meta.ts`; `runPreparedReply` now passes resolved envelope formatting options into `buildInboundUserContextPrefix`. Tests are updated/added to assert compact JSON output and the new `message_time` behavior.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- Changes are small and well-contained to prompt formatting: exporting an existing timestamp formatter, threading envelope options through one call site, and switching JSON output to compact form. Type definitions confirm `TemplateContext.Timestamp` is numeric, and repo-wide search shows no remaining references to the old private formatter name that would break builds.
- No files require special attention
<sub>Last reviewed commit: e80af47</sub>
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#19716: fix: inject timestamp into channel message agent context (#16442)
by chi777 · 2026-02-18
80.5%
#17017: feat(auto-reply): make agent time-aware with message timestamps
by liuy · 2026-02-15
80.3%
#16403: feat: add readable timestamp to inbound_meta.v1 payload
by mcinteerj · 2026-02-14
79.5%
#15407: feat: Add `message_id` to inbound metadata
by frosso · 2026-02-13
78.4%
#19923: feat: track held messages during compaction gate and split verifica...
by PrivacySmurf · 2026-02-18
77.7%
#2917: Slack: fix thread context + prevent reply spillover
by SocialNerd42069 · 2026-01-27
77.1%
#23271: fix(chat): strip untrusted metadata blocks from Control UI messages
by lbo728 · 2026-02-22
76.5%
#20081: feat: post-compaction triage UX — fuzzy ok + stage-2 gate + Discord...
by PrivacySmurf · 2026-02-18
75.8%
#21271: fix(commands): pass channel/capabilities/shell/os to runtime in com...
by evansantos · 2026-02-19
75.4%
#15395: Auto-reply: strip leaked protocol transcript lines from inbound con...
by kiranjd · 2026-02-13
75.1%