UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

82 lines • 3.38 kB
function validTimeZone(zone) { if (zone === undefined || zone.trim() === '') return 'UTC'; try { new Intl.DateTimeFormat('en-US', { timeZone: zone }); return zone; } catch { return 'UTC'; } } /** * `[sent 2026-10-23T11:17-03:00]` — ISO 8601 to the minute, with the zone's offset (`Z` in UTC): * locale-neutral, and unambiguous to the model whatever language the conversation is in. */ export function defaultMessageTimestampFormat(sentAt, ctx) { const parts = new Intl.DateTimeFormat('en-US', { timeZone: validTimeZone(ctx.timeZone), year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hourCycle: 'h23', timeZoneName: 'longOffset', }).formatToParts(sentAt); const part = (type) => parts.find((candidate) => candidate.type === type)?.value ?? ''; // `GMT-03:00` → `-03:00`; a zero offset (`GMT`, `GMT+00:00`) → `Z`. const shift = part('timeZoneName').replace(/^GMT/, ''); const offset = shift === '' || /^[+-]00:00$/.test(shift) ? 'Z' : shift; return `[sent ${part('year')}-${part('month')}-${part('day')}T${part('hour')}:${part('minute')}${offset}]`; } /** * A message's send time: the one recorded with it (`sentAt` — a channel's provider timestamp, a * send that named one, the moment a queued send was queued), else when it was stored. */ export function messageSentAt(message) { for (const value of [message.sentAt, message.createdAt]) { if (value === undefined) continue; const at = new Date(value); if (!Number.isNaN(at.getTime())) return at; } return null; } /** Builds the per-turn labeller: resolves the zone once, then labels each user message. */ export function messageTimestampLabeller(config, turn) { const zone = validTimeZone(typeof config.timeZone === 'function' ? config.timeZone(turn.actor) : config.timeZone); const format = config.format ?? defaultMessageTimestampFormat; return (stored, model) => { // A person's message, not the tool-results half of an exchange. if (model.role !== 'user' || (model.toolResults?.length ?? 0) > 0) return model; const sentAt = messageSentAt(stored); if (sentAt === null) return model; const label = format(sentAt, { actor: turn.actor, threadId: turn.threadId, timeZone: zone, message: { role: model.role, content: model.content }, }); if (label === '') return model; return { ...model, content: model.content === '' ? label : `${label} ${model.content}` }; }; } /** * A send time as the store keeps it (ISO 8601), from what a caller handed over: a `Date`, an ISO * string or epoch milliseconds. `undefined` for anything unreadable; a time in the future (a client * clock ahead of ours) is taken as `now`. */ export function normalizeSentAt(value, now = Date.now()) { if (value === undefined || value === null || value === '') return undefined; const at = value instanceof Date ? value.getTime() : new Date(value).getTime(); if (!Number.isFinite(at) || at <= 0) return undefined; return new Date(Math.min(at, now)).toISOString(); } //# sourceMappingURL=message-timestamps.js.map