@poncho-ai/harness 0.22.1 → 0.23.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.22.1 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.23.0 build /Users/cesar/Dev/latitude/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -8,8 +8,8 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 260.03 KB
12
- ESM ⚡️ Build success in 131ms
11
+ ESM dist/index.js 261.68 KB
12
+ ESM ⚡️ Build success in 128ms
13
13
  DTS Build start
14
- DTS ⚡️ Build success in 6723ms
15
- DTS dist/index.d.ts 27.15 KB
14
+ DTS ⚡️ Build success in 4463ms
15
+ DTS dist/index.d.ts 27.40 KB
@@ -0,0 +1,6 @@
1
+
2
+ > @poncho-ai/harness@0.11.2 lint /Users/cesar/Dev/latitude/poncho-ai/packages/harness
3
+ > eslint src/
4
+
5
+ sh: eslint: command not found
6
+  ELIFECYCLE  Command failed.
@@ -0,0 +1,135 @@
1
+
2
+ > @poncho-ai/harness@0.16.1 test /Users/cesar/Dev/latitude/poncho-ai/packages/harness
3
+ > vitest
4
+
5
+
6
+  RUN  v1.6.1 /Users/cesar/Dev/latitude/poncho-ai/packages/harness
7
+
8
+ ✓ test/telemetry.test.ts  (3 tests) 2ms
9
+ [event] step:completed {"type":"step:completed","step":1,"duration":1}
10
+ [event] step:started {"type":"step:started","step":2}
11
+ ✓ test/schema-converter.test.ts  (27 tests) 19ms
12
+ stdout | test/mcp.test.ts > mcp bridge protocol transports > discovers and calls tools over streamable HTTP
13
+ [poncho][mcp] {"event":"catalog.loaded","server":"remote","discoveredCount":1}
14
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":1,"filteredByPolicyCount":0,"filteredByIntentCount":0}
15
+
16
+ stdout | test/mcp.test.ts > mcp bridge protocol transports > selects discovered tools by requested patterns
17
+ [poncho][mcp] {"event":"catalog.loaded","server":"remote","discoveredCount":2}
18
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":1,"filteredByPolicyCount":0,"filteredByIntentCount":1}
19
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":2,"filteredByPolicyCount":0,"filteredByIntentCount":0}
20
+
21
+ ✓ test/agent-parser.test.ts  (10 tests) 24ms
22
+ stdout | test/mcp.test.ts > mcp bridge protocol transports > skips discovery when bearer token env value is missing
23
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":0,"filteredByPolicyCount":0,"filteredByIntentCount":0}
24
+
25
+ stderr | test/mcp.test.ts > mcp bridge protocol transports > skips discovery when bearer token env value is missing
26
+ [poncho][mcp] {"event":"auth.token_missing","server":"remote","tokenEnv":"MISSING_TOKEN_ENV"}
27
+
28
+ stdout | test/mcp.test.ts > mcp bridge protocol transports > returns actionable errors for 403 permission failures
29
+ [poncho][mcp] {"event":"catalog.loaded","server":"remote","discoveredCount":1}
30
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":1,"filteredByPolicyCount":0,"filteredByIntentCount":0}
31
+
32
+ ✓ test/mcp.test.ts  (6 tests) 81ms
33
+ ✓ test/memory.test.ts  (4 tests) 56ms
34
+ ✓ test/state.test.ts  (5 tests) 237ms
35
+ ✓ test/model-factory.test.ts  (4 tests) 2ms
36
+ ✓ test/agent-identity.test.ts  (2 tests) 43ms
37
+ stdout | test/harness.test.ts > agent harness > registers default filesystem tools
38
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
39
+
40
+ stdout | test/harness.test.ts > agent harness > disables write_file by default in production environment
41
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
42
+
43
+ stdout | test/harness.test.ts > agent harness > allows disabling built-in tools via poncho.config.js
44
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
45
+
46
+ stdout | test/harness.test.ts > agent harness > supports per-environment tool overrides
47
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
48
+
49
+ stdout | test/harness.test.ts > agent harness > supports per-environment tool overrides
50
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
51
+
52
+ stdout | test/harness.test.ts > agent harness > does not auto-register exported tool objects from skill scripts
53
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
54
+
55
+ stdout | test/harness.test.ts > agent harness > refreshes skill metadata and tools in development mode
56
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
57
+
58
+ stdout | test/harness.test.ts > agent harness > refreshes skill metadata and tools in development mode
59
+ [poncho][mcp] {"event":"tools.cleared","reason":"skills:changed","requestedPatterns":[]}
60
+ [poncho][mcp] {"event":"tools.cleared","reason":"activate:beta","requestedPatterns":[]}
61
+
62
+ stdout | test/harness.test.ts > agent harness > prunes removed active skills after refresh in development mode
63
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
64
+ [poncho][mcp] {"event":"tools.cleared","reason":"activate:obsolete","requestedPatterns":[]}
65
+
66
+ stdout | test/harness.test.ts > agent harness > prunes removed active skills after refresh in development mode
67
+ [poncho][mcp] {"event":"tools.cleared","reason":"skills:changed","requestedPatterns":[]}
68
+
69
+ stdout | test/harness.test.ts > agent harness > does not refresh skills outside development mode
70
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
71
+
72
+ stdout | test/harness.test.ts > agent harness > clears active skills when skill metadata changes in development mode
73
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
74
+ [poncho][mcp] {"event":"tools.cleared","reason":"activate:alpha","requestedPatterns":[]}
75
+
76
+ stdout | test/harness.test.ts > agent harness > clears active skills when skill metadata changes in development mode
77
+ [poncho][mcp] {"event":"tools.cleared","reason":"skills:changed","requestedPatterns":[]}
78
+
79
+ stdout | test/harness.test.ts > agent harness > lists skill scripts through list_skill_scripts
80
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
81
+
82
+ stdout | test/harness.test.ts > agent harness > runs JavaScript/TypeScript skill scripts through run_skill_script
83
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
84
+
85
+ stdout | test/harness.test.ts > agent harness > runs AGENT-scope scripts from root scripts directory
86
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
87
+
88
+ stdout | test/harness.test.ts > agent harness > blocks path traversal in run_skill_script
89
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
90
+
91
+ stdout | test/harness.test.ts > agent harness > requires allowed-tools entries for non-standard script directories
92
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
93
+
94
+ stdout | test/harness.test.ts > agent harness > registers MCP tools dynamically for stacked active skills and supports deactivation
95
+ [poncho][mcp] {"event":"catalog.loaded","server":"remote","discoveredCount":2}
96
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
97
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":1,"filteredByPolicyCount":0,"filteredByIntentCount":1}
98
+ [poncho][mcp] {"event":"tools.refreshed","reason":"activate:skill-a","requestedPatterns":["remote/a"],"registeredCount":1,"activeSkills":["skill-a"]}
99
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":2,"registeredCount":2,"filteredByPolicyCount":0,"filteredByIntentCount":0}
100
+ [poncho][mcp] {"event":"tools.refreshed","reason":"activate:skill-b","requestedPatterns":["remote/a","remote/b"],"registeredCount":2,"activeSkills":["skill-a","skill-b"]}
101
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":1,"filteredByPolicyCount":0,"filteredByIntentCount":1}
102
+ [poncho][mcp] {"event":"tools.refreshed","reason":"deactivate:skill-a","requestedPatterns":["remote/b"],"registeredCount":1,"activeSkills":["skill-b"]}
103
+
104
+ stdout | test/harness.test.ts > agent harness > supports flat tool access config format
105
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
106
+
107
+ stdout | test/harness.test.ts > agent harness > flat tool access takes priority over legacy defaults
108
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
109
+
110
+ stdout | test/harness.test.ts > agent harness > byEnvironment overrides flat tool access
111
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
112
+
113
+ stdout | test/harness.test.ts > agent harness > registerTools skips tools disabled via config
114
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
115
+
116
+ stdout | test/harness.test.ts > agent harness > approval access level registers the tool but marks it for approval
117
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
118
+
119
+ stdout | test/harness.test.ts > agent harness > tools without approval config do not require approval
120
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
121
+
122
+ stdout | test/harness.test.ts > agent harness > allows in-flight MCP calls to finish after skill deactivation
123
+ [poncho][mcp] {"event":"catalog.loaded","server":"remote","discoveredCount":1}
124
+ [poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
125
+ [poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":1,"filteredByPolicyCount":0,"filteredByIntentCount":0}
126
+ [poncho][mcp] {"event":"tools.refreshed","reason":"activate:skill-slow","requestedPatterns":["remote/slow"],"registeredCount":1,"activeSkills":["skill-slow"]}
127
+ [poncho][mcp] {"event":"tools.cleared","reason":"deactivate:skill-slow","requestedPatterns":[]}
128
+
129
+ ✓ test/harness.test.ts  (25 tests) 291ms
130
+
131
+  Test Files  9 passed (9)
132
+  Tests  86 passed (86)
133
+  Start at  17:47:43
134
+  Duration  1.88s (transform 684ms, setup 1ms, collect 2.34s, tests 755ms, environment 2ms, prepare 1.27s)
135
+
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.23.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`d1e1bfb`](https://github.com/cesr/poncho-ai/commit/d1e1bfbf35b18788ab79231ca675774e949f5116) Thanks [@cesr](https://github.com/cesr)! - Add proactive scheduled messaging via channel-targeted cron jobs. Cron jobs with `channel: telegram` (or `slack`) now automatically discover known conversations and send the agent's response directly to each chat, continuing the existing conversation history.
8
+
3
9
  ## 0.22.1
4
10
 
5
11
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ interface CronJobConfig {
19
19
  schedule: string;
20
20
  task: string;
21
21
  timezone?: string;
22
+ channel?: string;
22
23
  }
23
24
  interface AgentFrontmatter {
24
25
  name: string;
@@ -155,6 +156,11 @@ interface Conversation {
155
156
  result?: _poncho_ai_sdk.RunResult;
156
157
  error?: _poncho_ai_sdk.AgentFailure;
157
158
  };
159
+ channelMeta?: {
160
+ platform: string;
161
+ channelId: string;
162
+ platformThreadId: string;
163
+ };
158
164
  createdAt: number;
159
165
  updatedAt: number;
160
166
  }
@@ -208,6 +214,11 @@ type ConversationSummary = {
208
214
  parentConversationId?: string;
209
215
  messageCount?: number;
210
216
  hasPendingApprovals?: boolean;
217
+ channelMeta?: {
218
+ platform: string;
219
+ channelId: string;
220
+ platformThreadId: string;
221
+ };
211
222
  };
212
223
  declare const createStateStore: (config?: StateConfig, options?: {
213
224
  workingDir?: string;
package/dist/index.js CHANGED
@@ -112,10 +112,12 @@ var parseCronJobs = (value) => {
112
112
  if (timezone) {
113
113
  validateTimezone(timezone, path);
114
114
  }
115
+ const channel = typeof jobValue.channel === "string" && jobValue.channel.trim() ? jobValue.channel.trim() : void 0;
115
116
  jobs[jobName] = {
116
117
  schedule: jobValue.schedule.trim(),
117
118
  task: jobValue.task,
118
- timezone
119
+ timezone,
120
+ channel
119
121
  };
120
122
  }
121
123
  return jobs;
@@ -1030,6 +1032,22 @@ messaging: [
1030
1032
  ]
1031
1033
  \`\`\`
1032
1034
 
1035
+ #### Proactive scheduled messages
1036
+
1037
+ You can have the agent proactively message Telegram chats on a cron schedule. Add \`channel: telegram\` to any cron job in your \`AGENT.md\` frontmatter:
1038
+
1039
+ \`\`\`yaml
1040
+ cron:
1041
+ daily-checkin:
1042
+ schedule: "0 9 * * *"
1043
+ task: "Check in with the user about their plans for today"
1044
+ channel: telegram
1045
+ \`\`\`
1046
+
1047
+ The system auto-discovers all Telegram chats the bot has interacted with and sends the agent's response to each one. No chat IDs need to be configured -- filtering is handled by \`allowedUserIds\` if set. The agent runs with the full conversation history for each chat, so it has context from prior interactions.
1048
+
1049
+ The bot must have received at least one message from a user before it can send proactive messages to that chat (Telegram API requirement).
1050
+
1033
1051
  ### Email (Resend)
1034
1052
 
1035
1053
  #### 1. Set up Resend
@@ -4365,6 +4383,10 @@ cron:
4365
4383
  schedule: "0 9 * * *" # Standard 5-field cron expression
4366
4384
  timezone: "America/New_York" # Optional IANA timezone (default: UTC)
4367
4385
  task: "Generate the daily sales report"
4386
+ telegram-checkin:
4387
+ schedule: "0 18 * * 1-5"
4388
+ channel: telegram # Proactive message to all known Telegram chats
4389
+ task: "Send an end-of-day summary to the user"
4368
4390
  \`\`\`
4369
4391
 
4370
4392
  - Each cron job triggers an autonomous agent run with the specified task, creating a fresh conversation.
@@ -4373,6 +4395,7 @@ cron:
4373
4395
  - Jobs can also be triggered manually: \`GET /api/cron/<jobName>\`.
4374
4396
  - To carry context across cron runs, enable memory.
4375
4397
  - **IMPORTANT**: When adding a new cron job, always PRESERVE all existing cron jobs. Never remove or overwrite existing jobs unless the user explicitly asks you to replace or delete them. Read the full current \`cron:\` block before editing, and append the new job alongside the existing ones.
4398
+ - **Proactive channel messaging**: Adding \`channel: telegram\` (or \`slack\`) makes the cron job send its response directly to all known conversations on that platform, instead of creating a standalone conversation. The agent continues the existing conversation history for context. A chat must have at least one prior user message for auto-discovery to find it.
4376
4399
 
4377
4400
  ## Messaging Integrations (Slack, Telegram, Email)
4378
4401
 
@@ -6350,7 +6373,8 @@ var InMemoryConversationStore = class {
6350
6373
  ownerId: c.ownerId,
6351
6374
  parentConversationId: c.parentConversationId,
6352
6375
  messageCount: c.messages.length,
6353
- hasPendingApprovals: Array.isArray(c.pendingApprovals) && c.pendingApprovals.length > 0
6376
+ hasPendingApprovals: Array.isArray(c.pendingApprovals) && c.pendingApprovals.length > 0,
6377
+ channelMeta: c.channelMeta
6354
6378
  }));
6355
6379
  }
6356
6380
  async get(conversationId) {
@@ -6512,7 +6536,8 @@ var FileConversationStore = class {
6512
6536
  fileName,
6513
6537
  parentConversationId: conversation.parentConversationId,
6514
6538
  messageCount: conversation.messages.length,
6515
- hasPendingApprovals: Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0
6539
+ hasPendingApprovals: Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0,
6540
+ channelMeta: conversation.channelMeta
6516
6541
  });
6517
6542
  await this.writeIndex();
6518
6543
  });
@@ -6540,7 +6565,8 @@ var FileConversationStore = class {
6540
6565
  ownerId: c.ownerId,
6541
6566
  parentConversationId: c.parentConversationId,
6542
6567
  messageCount: c.messageCount,
6543
- hasPendingApprovals: c.hasPendingApprovals
6568
+ hasPendingApprovals: c.hasPendingApprovals,
6569
+ channelMeta: c.channelMeta
6544
6570
  }));
6545
6571
  }
6546
6572
  async get(conversationId) {
@@ -6806,7 +6832,8 @@ var KeyValueConversationStoreBase = class {
6806
6832
  ownerId: meta.ownerId,
6807
6833
  parentConversationId: meta.parentConversationId,
6808
6834
  messageCount: meta.messageCount,
6809
- hasPendingApprovals: meta.hasPendingApprovals
6835
+ hasPendingApprovals: meta.hasPendingApprovals,
6836
+ channelMeta: meta.channelMeta
6810
6837
  });
6811
6838
  }
6812
6839
  } catch {
@@ -6867,7 +6894,8 @@ var KeyValueConversationStoreBase = class {
6867
6894
  ownerId: nextConversation.ownerId,
6868
6895
  parentConversationId: nextConversation.parentConversationId,
6869
6896
  messageCount: nextConversation.messages.length,
6870
- hasPendingApprovals: Array.isArray(nextConversation.pendingApprovals) && nextConversation.pendingApprovals.length > 0
6897
+ hasPendingApprovals: Array.isArray(nextConversation.pendingApprovals) && nextConversation.pendingApprovals.length > 0,
6898
+ channelMeta: nextConversation.channelMeta
6871
6899
  }),
6872
6900
  this.ttl
6873
6901
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.22.1",
3
+ "version": "0.23.0",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,6 +27,7 @@ export interface CronJobConfig {
27
27
  schedule: string;
28
28
  task: string;
29
29
  timezone?: string;
30
+ channel?: string;
30
31
  }
31
32
 
32
33
  export interface AgentFrontmatter {
@@ -138,10 +139,16 @@ const parseCronJobs = (
138
139
  validateTimezone(timezone, path);
139
140
  }
140
141
 
142
+ const channel =
143
+ typeof jobValue.channel === "string" && jobValue.channel.trim()
144
+ ? jobValue.channel.trim()
145
+ : undefined;
146
+
141
147
  jobs[jobName] = {
142
148
  schedule: jobValue.schedule.trim(),
143
149
  task: jobValue.task,
144
150
  timezone,
151
+ channel,
145
152
  };
146
153
  }
147
154
  return jobs;
package/src/harness.ts CHANGED
@@ -280,6 +280,10 @@ cron:
280
280
  schedule: "0 9 * * *" # Standard 5-field cron expression
281
281
  timezone: "America/New_York" # Optional IANA timezone (default: UTC)
282
282
  task: "Generate the daily sales report"
283
+ telegram-checkin:
284
+ schedule: "0 18 * * 1-5"
285
+ channel: telegram # Proactive message to all known Telegram chats
286
+ task: "Send an end-of-day summary to the user"
283
287
  \`\`\`
284
288
 
285
289
  - Each cron job triggers an autonomous agent run with the specified task, creating a fresh conversation.
@@ -288,6 +292,7 @@ cron:
288
292
  - Jobs can also be triggered manually: \`GET /api/cron/<jobName>\`.
289
293
  - To carry context across cron runs, enable memory.
290
294
  - **IMPORTANT**: When adding a new cron job, always PRESERVE all existing cron jobs. Never remove or overwrite existing jobs unless the user explicitly asks you to replace or delete them. Read the full current \`cron:\` block before editing, and append the new job alongside the existing ones.
295
+ - **Proactive channel messaging**: Adding \`channel: telegram\` (or \`slack\`) makes the cron job send its response directly to all known conversations on that platform, instead of creating a standalone conversation. The agent continues the existing conversation history for context. A chat must have at least one prior user message for auto-discovery to find it.
291
296
 
292
297
  ## Messaging Integrations (Slack, Telegram, Email)
293
298
 
package/src/state.ts CHANGED
@@ -50,6 +50,11 @@ export interface Conversation {
50
50
  result?: import("@poncho-ai/sdk").RunResult;
51
51
  error?: import("@poncho-ai/sdk").AgentFailure;
52
52
  };
53
+ channelMeta?: {
54
+ platform: string;
55
+ channelId: string;
56
+ platformThreadId: string;
57
+ };
53
58
  createdAt: number;
54
59
  updatedAt: number;
55
60
  }
@@ -247,6 +252,7 @@ export class InMemoryConversationStore implements ConversationStore {
247
252
  parentConversationId: c.parentConversationId,
248
253
  messageCount: c.messages.length,
249
254
  hasPendingApprovals: Array.isArray(c.pendingApprovals) && c.pendingApprovals.length > 0,
255
+ channelMeta: c.channelMeta,
250
256
  }));
251
257
  }
252
258
 
@@ -305,6 +311,11 @@ export type ConversationSummary = {
305
311
  parentConversationId?: string;
306
312
  messageCount?: number;
307
313
  hasPendingApprovals?: boolean;
314
+ channelMeta?: {
315
+ platform: string;
316
+ channelId: string;
317
+ platformThreadId: string;
318
+ };
308
319
  };
309
320
 
310
321
  type ConversationStoreFile = {
@@ -319,6 +330,11 @@ type ConversationStoreFile = {
319
330
  parentConversationId?: string;
320
331
  messageCount?: number;
321
332
  hasPendingApprovals?: boolean;
333
+ channelMeta?: {
334
+ platform: string;
335
+ channelId: string;
336
+ platformThreadId: string;
337
+ };
322
338
  }>;
323
339
  };
324
340
 
@@ -451,6 +467,7 @@ class FileConversationStore implements ConversationStore {
451
467
  parentConversationId: conversation.parentConversationId,
452
468
  messageCount: conversation.messages.length,
453
469
  hasPendingApprovals: Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0,
470
+ channelMeta: conversation.channelMeta,
454
471
  });
455
472
  await this.writeIndex();
456
473
  });
@@ -486,6 +503,7 @@ class FileConversationStore implements ConversationStore {
486
503
  parentConversationId: c.parentConversationId,
487
504
  messageCount: c.messageCount,
488
505
  hasPendingApprovals: c.hasPendingApprovals,
506
+ channelMeta: c.channelMeta,
489
507
  }));
490
508
  }
491
509
 
@@ -660,6 +678,11 @@ type ConversationMeta = {
660
678
  parentConversationId?: string;
661
679
  messageCount?: number;
662
680
  hasPendingApprovals?: boolean;
681
+ channelMeta?: {
682
+ platform: string;
683
+ channelId: string;
684
+ platformThreadId: string;
685
+ };
663
686
  };
664
687
 
665
688
  abstract class KeyValueConversationStoreBase implements ConversationStore {
@@ -804,6 +827,7 @@ abstract class KeyValueConversationStoreBase implements ConversationStore {
804
827
  parentConversationId: meta.parentConversationId,
805
828
  messageCount: meta.messageCount,
806
829
  hasPendingApprovals: meta.hasPendingApprovals,
830
+ channelMeta: meta.channelMeta,
807
831
  });
808
832
  }
809
833
  } catch { /* skip invalid records */ }
@@ -867,6 +891,7 @@ abstract class KeyValueConversationStoreBase implements ConversationStore {
867
891
  parentConversationId: nextConversation.parentConversationId,
868
892
  messageCount: nextConversation.messages.length,
869
893
  hasPendingApprovals: Array.isArray(nextConversation.pendingApprovals) && nextConversation.pendingApprovals.length > 0,
894
+ channelMeta: nextConversation.channelMeta,
870
895
  } satisfies ConversationMeta),
871
896
  this.ttl,
872
897
  );