@animalabs/agent-framework 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/src/agent.d.ts +3 -1
  2. package/dist/src/agent.d.ts.map +1 -1
  3. package/dist/src/agent.js +7 -2
  4. package/dist/src/agent.js.map +1 -1
  5. package/dist/src/framework.d.ts +60 -1
  6. package/dist/src/framework.d.ts.map +1 -1
  7. package/dist/src/framework.js +261 -20
  8. package/dist/src/framework.js.map +1 -1
  9. package/dist/src/index.d.ts +1 -0
  10. package/dist/src/index.d.ts.map +1 -1
  11. package/dist/src/index.js +1 -0
  12. package/dist/src/index.js.map +1 -1
  13. package/dist/src/modules/discord/index.d.ts +1 -0
  14. package/dist/src/modules/discord/index.d.ts.map +1 -1
  15. package/dist/src/modules/discord/index.js +4 -1
  16. package/dist/src/modules/discord/index.js.map +1 -1
  17. package/dist/src/modules/discord/types.d.ts +2 -0
  18. package/dist/src/modules/discord/types.d.ts.map +1 -1
  19. package/dist/src/modules/health/index.d.ts +2 -0
  20. package/dist/src/modules/health/index.d.ts.map +1 -1
  21. package/dist/src/modules/health/index.js +15 -4
  22. package/dist/src/modules/health/index.js.map +1 -1
  23. package/dist/src/timezone.d.ts +14 -0
  24. package/dist/src/timezone.d.ts.map +1 -0
  25. package/dist/src/timezone.js +74 -0
  26. package/dist/src/timezone.js.map +1 -0
  27. package/dist/src/types/agent.d.ts +5 -2
  28. package/dist/src/types/agent.d.ts.map +1 -1
  29. package/dist/src/types/framework.d.ts +46 -0
  30. package/dist/src/types/framework.d.ts.map +1 -1
  31. package/dist/src/types/trace.d.ts +9 -0
  32. package/dist/src/types/trace.d.ts.map +1 -1
  33. package/dist/test/agent-cache-ttl.test.js +18 -2
  34. package/dist/test/agent-cache-ttl.test.js.map +1 -1
  35. package/dist/test/health-snapshot.test.d.ts +2 -0
  36. package/dist/test/health-snapshot.test.d.ts.map +1 -0
  37. package/dist/test/health-snapshot.test.js +74 -0
  38. package/dist/test/health-snapshot.test.js.map +1 -0
  39. package/dist/test/inference-failure-observability.test.js +5 -0
  40. package/dist/test/inference-failure-observability.test.js.map +1 -1
  41. package/dist/test/maintenance-timer.test.d.ts +2 -0
  42. package/dist/test/maintenance-timer.test.d.ts.map +1 -0
  43. package/dist/test/maintenance-timer.test.js +114 -0
  44. package/dist/test/maintenance-timer.test.js.map +1 -0
  45. package/dist/test/ops-alert.test.d.ts +2 -0
  46. package/dist/test/ops-alert.test.d.ts.map +1 -0
  47. package/dist/test/ops-alert.test.js +152 -0
  48. package/dist/test/ops-alert.test.js.map +1 -0
  49. package/dist/test/timezone.test.d.ts +2 -0
  50. package/dist/test/timezone.test.d.ts.map +1 -0
  51. package/dist/test/timezone.test.js +18 -0
  52. package/dist/test/timezone.test.js.map +1 -0
  53. package/dist/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +1 -1
  55. package/src/agent.ts +8 -3
  56. package/src/framework.ts +307 -22
  57. package/src/index.ts +1 -0
  58. package/src/modules/discord/index.ts +4 -1
  59. package/src/modules/discord/types.ts +3 -0
  60. package/src/modules/health/index.ts +20 -4
  61. package/src/timezone.ts +90 -0
  62. package/src/types/agent.ts +6 -2
  63. package/src/types/framework.ts +51 -0
  64. package/src/types/trace.ts +16 -0
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Agent-visible wall-clock formatting.
3
+ *
4
+ * Persistence and protocol timestamps should remain epoch milliseconds or UTC
5
+ * ISO strings. These helpers are only for presentation boundaries where a
6
+ * timestamp is rendered into an agent's context or a tool result.
7
+ */
8
+
9
+ export function isValidTimeZone(timeZone: string): boolean {
10
+ try {
11
+ new Intl.DateTimeFormat('en-US', { timeZone }).format(new Date(0));
12
+ return true;
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+
18
+ export function resolveTimeZone(configured?: string): string {
19
+ const candidate = configured?.trim()
20
+ || process.env.AGENT_TIMEZONE?.trim()
21
+ || Intl.DateTimeFormat().resolvedOptions().timeZone
22
+ || 'UTC';
23
+ if (!isValidTimeZone(candidate)) {
24
+ throw new Error(`Invalid IANA time zone: ${JSON.stringify(candidate)}`);
25
+ }
26
+ return candidate;
27
+ }
28
+
29
+ type ZonedParts = {
30
+ year: string;
31
+ month: string;
32
+ day: string;
33
+ hour: string;
34
+ minute: string;
35
+ second: string;
36
+ };
37
+
38
+ function zonedParts(date: Date, timeZone: string): ZonedParts {
39
+ const parts = new Intl.DateTimeFormat('en-CA', {
40
+ timeZone,
41
+ year: 'numeric',
42
+ month: '2-digit',
43
+ day: '2-digit',
44
+ hour: '2-digit',
45
+ minute: '2-digit',
46
+ second: '2-digit',
47
+ hourCycle: 'h23',
48
+ }).formatToParts(date);
49
+ const get = (type: Intl.DateTimeFormatPartTypes): string =>
50
+ parts.find((part) => part.type === type)?.value ?? '';
51
+ return {
52
+ year: get('year'),
53
+ month: get('month'),
54
+ day: get('day'),
55
+ hour: get('hour'),
56
+ minute: get('minute'),
57
+ second: get('second'),
58
+ };
59
+ }
60
+
61
+ /** RFC3339-style local time with an explicit numeric offset and IANA zone. */
62
+ export function formatZonedDateTime(value: Date | number | string, timeZone: string): string {
63
+ const date = value instanceof Date ? value : new Date(value);
64
+ if (Number.isNaN(date.getTime())) throw new Error(`Invalid date: ${String(value)}`);
65
+ const zone = resolveTimeZone(timeZone);
66
+ const p = zonedParts(date, zone);
67
+
68
+ // Reinterpret the displayed wall-clock components as UTC to recover the
69
+ // offset that applied at this exact instant (including DST transitions).
70
+ const displayedAsUtc = Date.UTC(
71
+ Number(p.year), Number(p.month) - 1, Number(p.day),
72
+ Number(p.hour), Number(p.minute), Number(p.second),
73
+ );
74
+ const instantAtWholeSecond = Math.floor(date.getTime() / 1000) * 1000;
75
+ const offsetMinutes = Math.round((displayedAsUtc - instantAtWholeSecond) / 60_000);
76
+ const sign = offsetMinutes < 0 ? '-' : '+';
77
+ const absoluteOffset = Math.abs(offsetMinutes);
78
+ const offset = `${sign}${String(Math.floor(absoluteOffset / 60)).padStart(2, '0')}:${String(absoluteOffset % 60).padStart(2, '0')}`;
79
+ const millis = String(date.getUTCMilliseconds()).padStart(3, '0');
80
+
81
+ return `${p.year}-${p.month}-${p.day}T${p.hour}:${p.minute}:${p.second}.${millis}${offset} [${zone}]`;
82
+ }
83
+
84
+ /** Compact wall-clock time for provenance headers. */
85
+ export function formatZonedTime(value: Date | number | string, timeZone: string): string {
86
+ const date = value instanceof Date ? value : new Date(value);
87
+ if (Number.isNaN(date.getTime())) throw new Error(`Invalid date: ${String(value)}`);
88
+ const p = zonedParts(date, resolveTimeZone(timeZone));
89
+ return `${p.hour}:${p.minute}`;
90
+ }
@@ -48,7 +48,7 @@ export interface AgentConfig {
48
48
 
49
49
  /**
50
50
  * Prompt-cache TTL forwarded to the provider (Anthropic `cache_control.ttl`).
51
- * '5m' (provider default) or '1h'. When unset, Membrane's default applies.
51
+ * '5m' or '1h'. Defaults to '1h'.
52
52
  *
53
53
  * Why you'd set '1h': for persistent agents whose conversational cadence is
54
54
  * slower than 5 minutes, the default TTL expires between turns and the full
@@ -57,10 +57,14 @@ export interface AgentConfig {
57
57
  * chatty-but-not-rapid agent pays the write premium over and over. With '1h'
58
58
  * the write happens once per idle-hour and subsequent turns hit cache reads;
59
59
  * in practice cache writes can dominate spend for slow-cadence agents.
60
- * Keep '5m' (or unset) for high-frequency loops with sub-5-minute cadence,
60
+ * Set '5m' explicitly for high-frequency loops with sub-5-minute cadence,
61
61
  * where the cheaper write premium wins.
62
62
  */
63
63
  cacheTtl?: '5m' | '1h';
64
+
65
+ /** Provider-specific request parameters (for example Responses reasoning
66
+ * and server-side compaction settings). */
67
+ providerParams?: Record<string, unknown>;
64
68
  /**
65
69
  * Extended thinking config. When `enabled: true`, the agent runs with
66
70
  * Anthropic's native extended thinking; responses include `thinking` blocks
@@ -32,6 +32,13 @@ export interface ProcessLoggingConfig {
32
32
  * Configuration for the agent framework.
33
33
  */
34
34
  export interface FrameworkConfig {
35
+ /**
36
+ * IANA zone used only when rendering wall-clock times for the agent.
37
+ * Stored/protocol timestamps remain epoch/UTC. Defaults to AGENT_TIMEZONE,
38
+ * then the process zone.
39
+ */
40
+ timeZone?: string;
41
+
35
42
  /** Path to Chronicle store */
36
43
  storePath?: string;
37
44
 
@@ -56,6 +63,13 @@ export interface FrameworkConfig {
56
63
  /** Interval for periodic store sync in milliseconds (default: 1000ms, 0 to disable) */
57
64
  syncIntervalMs?: number;
58
65
 
66
+ /**
67
+ * Interval for queued context-maintenance polling in milliseconds
68
+ * (default: 5000ms, 0 to disable). Each pass refreshes the agent's live tool
69
+ * definitions, then advances pending compression/indexing work.
70
+ */
71
+ maintenanceIntervalMs?: number;
72
+
59
73
  /** Process logging configuration (default: disabled) */
60
74
  processLogging?: ProcessLoggingConfig;
61
75
 
@@ -92,6 +106,43 @@ export interface FrameworkConfig {
92
106
  conversations?: ConversationRouterConfig;
93
107
  }
94
108
 
109
+ /** One agent's outcome within a periodic context-maintenance pass. */
110
+ export interface ContextMaintenanceAgentRun {
111
+ agentName: string;
112
+ startedAt: number;
113
+ finishedAt?: number;
114
+ ticks: number;
115
+ readyBefore: boolean;
116
+ readyAfter?: boolean;
117
+ pendingBefore?: string;
118
+ pendingAfter?: string;
119
+ progressBefore?: Record<string, unknown>;
120
+ progressAfter?: Record<string, unknown>;
121
+ error?: string;
122
+ }
123
+
124
+ /** A bounded periodic context-maintenance pass. */
125
+ export interface ContextMaintenanceRun {
126
+ id: number;
127
+ startedAt: number;
128
+ finishedAt?: number;
129
+ agents: ContextMaintenanceAgentRun[];
130
+ }
131
+
132
+ /** Debug-safe maintenance state. Contains counts and errors, never messages. */
133
+ export interface ContextMaintenanceSnapshot {
134
+ intervalMs: number;
135
+ ticksPerPass: number;
136
+ current: ContextMaintenanceRun | null;
137
+ history: ContextMaintenanceRun[];
138
+ agents: Array<{
139
+ agentName: string;
140
+ ready: boolean;
141
+ pending?: string;
142
+ progress?: Record<string, unknown>;
143
+ }>;
144
+ }
145
+
95
146
  /**
96
147
  * Policy for deciding when to run inference.
97
148
  */
@@ -321,6 +321,22 @@ export type TraceEvent =
321
321
  hadState: boolean;
322
322
  /** True when the dropped response carried a server-managed `checkpoint`. */
323
323
  hadCheckpoint: boolean;
324
+ })
325
+
326
+ // Ops / fleet observability. Everything the framework's opsAlert() escalates
327
+ // (refusals, hard-down, MCPL unreachable, …) mirrored onto the trace bus so
328
+ // authorized observers see alerts on the same wire as the rest of the
329
+ // agent's internal life. Discord (CONNECTOME_OPS_WEBHOOK) is one sink of
330
+ // this stream, not a separate system. See connectome docs/observability.md.
331
+ | (TraceEventBase & {
332
+ type: 'ops:alert';
333
+ /** Alert kind — open set: 'refusal' | 'hard-down' | 'mcpl-down' | … */
334
+ kind: string;
335
+ /** Agent name, or a server/component id for non-agent alerts (e.g. mcpl-down). */
336
+ agentName: string;
337
+ message: string;
338
+ /** Kind-specific structured payload (mirrors the failures.log record). */
339
+ data?: Record<string, unknown>;
324
340
  });
325
341
 
326
342
  /**