@animalabs/agent-framework 0.13.0 → 0.15.0

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 (95) hide show
  1. package/dist/src/agent.d.ts +10 -0
  2. package/dist/src/agent.d.ts.map +1 -1
  3. package/dist/src/agent.js +39 -0
  4. package/dist/src/agent.js.map +1 -1
  5. package/dist/src/framework.d.ts +36 -6
  6. package/dist/src/framework.d.ts.map +1 -1
  7. package/dist/src/framework.js +451 -83
  8. package/dist/src/framework.js.map +1 -1
  9. package/dist/src/gate/event-gate.d.ts +55 -1
  10. package/dist/src/gate/event-gate.d.ts.map +1 -1
  11. package/dist/src/gate/event-gate.js +41 -1
  12. package/dist/src/gate/event-gate.js.map +1 -1
  13. package/dist/src/gate/index.d.ts +1 -1
  14. package/dist/src/gate/index.d.ts.map +1 -1
  15. package/dist/src/gate/index.js +1 -1
  16. package/dist/src/gate/index.js.map +1 -1
  17. package/dist/src/index.d.ts +1 -1
  18. package/dist/src/index.d.ts.map +1 -1
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/modules/history/index.d.ts +69 -0
  21. package/dist/src/modules/history/index.d.ts.map +1 -0
  22. package/dist/src/modules/history/index.js +519 -0
  23. package/dist/src/modules/history/index.js.map +1 -0
  24. package/dist/src/modules/history/search-regex-worker.d.ts +23 -0
  25. package/dist/src/modules/history/search-regex-worker.d.ts.map +1 -0
  26. package/dist/src/modules/history/search-regex-worker.js +57 -0
  27. package/dist/src/modules/history/search-regex-worker.js.map +1 -0
  28. package/dist/src/modules/index.d.ts +1 -0
  29. package/dist/src/modules/index.d.ts.map +1 -1
  30. package/dist/src/modules/index.js +1 -0
  31. package/dist/src/modules/index.js.map +1 -1
  32. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  33. package/dist/src/modules/workspace/index.js +42 -1
  34. package/dist/src/modules/workspace/index.js.map +1 -1
  35. package/dist/src/modules/workspace/types.d.ts +5 -0
  36. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  37. package/dist/src/modules/workspace/types.js.map +1 -1
  38. package/dist/src/tool-image-ledger.d.ts +175 -0
  39. package/dist/src/tool-image-ledger.d.ts.map +1 -0
  40. package/dist/src/tool-image-ledger.js +257 -0
  41. package/dist/src/tool-image-ledger.js.map +1 -0
  42. package/dist/src/tool-result-history.d.ts +15 -2
  43. package/dist/src/tool-result-history.d.ts.map +1 -1
  44. package/dist/src/tool-result-history.js +16 -9
  45. package/dist/src/tool-result-history.js.map +1 -1
  46. package/dist/src/types/agent.d.ts +10 -0
  47. package/dist/src/types/agent.d.ts.map +1 -1
  48. package/dist/src/types/trace.d.ts +4 -0
  49. package/dist/src/types/trace.d.ts.map +1 -1
  50. package/dist/test/event-gate.test.js +84 -1
  51. package/dist/test/event-gate.test.js.map +1 -1
  52. package/dist/test/history-module.test.d.ts +2 -0
  53. package/dist/test/history-module.test.d.ts.map +1 -0
  54. package/dist/test/history-module.test.js +449 -0
  55. package/dist/test/history-module.test.js.map +1 -0
  56. package/dist/test/kv-unified-open-flight-retry.test.d.ts +2 -0
  57. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +1 -0
  58. package/dist/test/kv-unified-open-flight-retry.test.js +189 -0
  59. package/dist/test/kv-unified-open-flight-retry.test.js.map +1 -0
  60. package/dist/test/kv-unified-wiring.test.js +39 -0
  61. package/dist/test/kv-unified-wiring.test.js.map +1 -1
  62. package/dist/test/puppet-tool-call.test.js +114 -1
  63. package/dist/test/puppet-tool-call.test.js.map +1 -1
  64. package/dist/test/puppet-turn-reservation.test.d.ts +2 -0
  65. package/dist/test/puppet-turn-reservation.test.d.ts.map +1 -0
  66. package/dist/test/puppet-turn-reservation.test.js +139 -0
  67. package/dist/test/puppet-turn-reservation.test.js.map +1 -0
  68. package/dist/test/save-recent-image.test.d.ts +26 -0
  69. package/dist/test/save-recent-image.test.d.ts.map +1 -0
  70. package/dist/test/save-recent-image.test.js +736 -0
  71. package/dist/test/save-recent-image.test.js.map +1 -0
  72. package/dist/test/tool-result-spill.test.js +114 -0
  73. package/dist/test/tool-result-spill.test.js.map +1 -1
  74. package/dist/test/turn-trigger-provenance.test.js +17 -0
  75. package/dist/test/turn-trigger-provenance.test.js.map +1 -1
  76. package/dist/test/workspace-read-text.test.d.ts +2 -0
  77. package/dist/test/workspace-read-text.test.d.ts.map +1 -0
  78. package/dist/test/workspace-read-text.test.js +101 -0
  79. package/dist/test/workspace-read-text.test.js.map +1 -0
  80. package/dist/tsconfig.tsbuildinfo +1 -1
  81. package/package.json +3 -3
  82. package/src/agent.ts +41 -0
  83. package/src/framework.ts +519 -95
  84. package/src/gate/event-gate.ts +71 -3
  85. package/src/gate/index.ts +1 -1
  86. package/src/index.ts +1 -1
  87. package/src/modules/history/index.ts +613 -0
  88. package/src/modules/history/search-regex-worker.ts +76 -0
  89. package/src/modules/index.ts +2 -0
  90. package/src/modules/workspace/index.ts +42 -1
  91. package/src/modules/workspace/types.ts +5 -0
  92. package/src/tool-image-ledger.ts +334 -0
  93. package/src/tool-result-history.ts +30 -9
  94. package/src/types/agent.ts +10 -0
  95. package/src/types/trace.ts +4 -0
@@ -78,6 +78,37 @@ interface PendingEvent {
78
78
  * metadata carries one — batched-wake lines render this instead of the raw
79
79
  * composite channel id. */
80
80
  channelLabel?: string;
81
+ /** Author id of the event (discord snowflake etc.), when the metadata carries
82
+ * one — a debounced wake names the newest such author as its counterparty. */
83
+ authorId?: string;
84
+ /** MCPL server id the event came from — the namespace for the counterparty
85
+ * (`<serverId>:user:<id>`), same as the direct channel-incoming path. */
86
+ serverId?: string;
87
+ /** `chat:addressed` (mention / reply-to-bot / DM): an addressed event outranks
88
+ * newer ambient chatter when a batched wake picks its provenance — the same
89
+ * rule the framework applies to the turn's speech locus. */
90
+ addressed: boolean;
91
+ }
92
+
93
+ /**
94
+ * Where a gate-requested wake came from, handed to the framework alongside the
95
+ * reason so the turn's InferenceRequest can carry it (host telemetry stamps
96
+ * "who woke the agent" from it). Ids only, never content or display names.
97
+ */
98
+ export interface WakeProvenance {
99
+ /** Composite channel id of the chosen event — telemetry only, never a
100
+ * speech locus. Omitted for `mcpl:push-event` events, whose channel ids
101
+ * are raw server ids (unroutable and a second spelling of the same
102
+ * channel); the framework derives the composite id on the direct path. */
103
+ channelId?: string;
104
+ /** Server-namespaced author id: `<serverId>:user:<id>` (falls back to the
105
+ * channel id's first segment only when the event carried no server id). */
106
+ counterparty?: string;
107
+ /** True when the chosen event was `chat:addressed`. */
108
+ addressed?: boolean;
109
+ /** Timestamp (ms) of the chosen event, so a consumer coalescing several
110
+ * requests can order by event recency, not by flush order. */
111
+ at?: number;
81
112
  }
82
113
 
83
114
  interface DebounceState {
@@ -149,6 +180,34 @@ function isMetadataTruthy(value: unknown): boolean {
149
180
  return Boolean(value);
150
181
  }
151
182
 
183
+ /**
184
+ * Provenance of a batched wake: the newest ADDRESSED channel-bearing event
185
+ * wins (mention / reply / DM outranks newer ambient chatter — the framework's
186
+ * own locus rule); else the newest channel-bearing event. Channel, author and
187
+ * addressed all come from that one event, so they can never disagree.
188
+ */
189
+ export function wakeProvenance(events: PendingEvent[]): WakeProvenance | undefined {
190
+ let newest: PendingEvent | undefined;
191
+ let newestAddressed: PendingEvent | undefined;
192
+ for (const e of events) {
193
+ if (!e.channelId && !e.authorId) continue;
194
+ if (!newest || e.timestamp >= newest.timestamp) newest = e;
195
+ if (e.addressed && (!newestAddressed || e.timestamp >= newestAddressed.timestamp)) newestAddressed = e;
196
+ }
197
+ const pick = newestAddressed ?? newest;
198
+ if (!pick) return undefined;
199
+ // push-event channel ids are the adapter's raw ids (a Discord snowflake):
200
+ // not a composite channel id, so not reported as one
201
+ const channelId = pick.channelId && pick.eventType !== 'mcpl:push-event' ? pick.channelId : undefined;
202
+ const ns = pick.serverId || (pick.channelId ? pick.channelId.split(':')[0] : '') || 'channel';
203
+ return {
204
+ ...(channelId ? { channelId } : {}),
205
+ ...(pick.authorId ? { counterparty: `${ns}:user:${pick.authorId}` } : {}),
206
+ ...(pick.addressed ? { addressed: true } : {}),
207
+ at: pick.timestamp,
208
+ };
209
+ }
210
+
152
211
  /** Compact, log-friendly serialization of a GateBehavior. */
153
212
  function formatBehavior(b: import('./types.js').GateBehavior): string {
154
213
  if (typeof b === 'string') return b;
@@ -522,7 +581,7 @@ export class EventGate {
522
581
  /** Registry agent to deliver into; absent = primary (historical). */
523
582
  forAgent?: string,
524
583
  ) => unknown;
525
- private requestInferenceFn: (agentName: string, reason: string, source: string) => void;
584
+ private requestInferenceFn: (agentName: string, reason: string, source: string, provenance?: WakeProvenance) => void;
526
585
  private getAgentNamesFn: () => string[];
527
586
  /** Clock injection — keeps the new rate_limit / passive_sample paths
528
587
  * testable without monkey-patching Date.now globally. */
@@ -539,7 +598,7 @@ export class EventGate {
539
598
  metadata?: Record<string, unknown>,
540
599
  forAgent?: string,
541
600
  ) => unknown;
542
- requestInference: (agentName: string, reason: string, source: string) => void;
601
+ requestInference: (agentName: string, reason: string, source: string, provenance?: WakeProvenance) => void;
543
602
  getAgentNames: () => string[];
544
603
  /** Optional clock — defaults to Date.now. Tests inject for deterministic time. */
545
604
  now?: () => number;
@@ -1385,6 +1444,9 @@ export class EventGate {
1385
1444
  typeof info.metadata?.channelName === 'string' && info.metadata.channelName
1386
1445
  ? (info.metadata.channelName as string)
1387
1446
  : undefined,
1447
+ authorId: this.extractAuthorId(info.metadata) ?? undefined,
1448
+ serverId: info.serverId || undefined,
1449
+ addressed: Array.isArray(info.tags) && info.tags.includes('chat:addressed'),
1388
1450
  };
1389
1451
 
1390
1452
  const existing = this.debounceTimers.get(policy.name);
@@ -1472,8 +1534,14 @@ export class EventGate {
1472
1534
  policies: policyNames,
1473
1535
  });
1474
1536
 
1537
+ // Provenance of the batched wake (telemetry: who/where woke the agent):
1538
+ // the newest ADDRESSED event first, else the newest event naming a
1539
+ // channel or an author; channel + author + addressed from that ONE
1540
+ // event. It does not set the turn's speech locus — the framework keeps
1541
+ // its own routing rule for that.
1542
+ const provenance = wakeProvenance(events);
1475
1543
  for (const agentName of this.getAgentNamesFn()) {
1476
- this.requestInferenceFn(agentName, 'gate:debounce', 'gate');
1544
+ this.requestInferenceFn(agentName, 'gate:debounce', 'gate', provenance);
1477
1545
  }
1478
1546
  }
1479
1547
 
package/src/gate/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { EventGate } from './event-gate.js';
1
+ export { EventGate, wakeProvenance, type WakeProvenance } from './event-gate.js';
2
2
  export type {
3
3
  GateConfig,
4
4
  GateOptions,
package/src/index.ts CHANGED
@@ -76,7 +76,7 @@ export type {
76
76
  export type { SessionUsage, AgentUsage, SessionUsageSnapshot, UsageUpdatedEvent } from './usage/index.js';
77
77
 
78
78
  // EventGate
79
- export { EventGate } from './gate/index.js';
79
+ export { EventGate, type WakeProvenance } from './gate/index.js';
80
80
  export type { GateConfig, GateOptions, GatePolicy, GatePolicyMatch, GateBehavior } from './gate/index.js';
81
81
 
82
82
  // MCPL channel registry (exposed for modules that need channel-level operations)