@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.
- package/.turbo/turbo-build.log +5 -5
- package/.turbo/turbo-lint.log +6 -0
- package/.turbo/turbo-test.log +135 -0
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +34 -6
- package/package.json +1 -1
- package/src/agent-parser.ts +7 -0
- package/src/harness.ts +5 -0
- package/src/state.ts +25 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @poncho-ai/harness@0.
|
|
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
|
[34mCLI[39m tsup v8.5.1
|
|
9
9
|
[34mCLI[39m Target: es2022
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
-
[32mESM[39m [1mdist/index.js [22m[
|
|
12
|
-
[32mESM[39m ⚡️ Build success in
|
|
11
|
+
[32mESM[39m [1mdist/index.js [22m[32m261.68 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 128ms
|
|
13
13
|
[34mDTS[39m Build start
|
|
14
|
-
[32mDTS[39m ⚡️ Build success in
|
|
15
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m27.
|
|
14
|
+
[32mDTS[39m ⚡️ Build success in 4463ms
|
|
15
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m27.40 KB[39m
|
|
@@ -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
|
+
[7m[1m[36m RUN [39m[22m[27m [36mv1.6.1[39m [90m/Users/cesar/Dev/latitude/poncho-ai/packages/harness[39m
|
|
7
|
+
|
|
8
|
+
[32m✓[39m test/telemetry.test.ts [2m ([22m[2m3 tests[22m[2m)[22m[90m 2[2mms[22m[39m
|
|
9
|
+
[event] step:completed {"type":"step:completed","step":1,"duration":1}
|
|
10
|
+
[event] step:started {"type":"step:started","step":2}
|
|
11
|
+
[32m✓[39m test/schema-converter.test.ts [2m ([22m[2m27 tests[22m[2m)[22m[90m 19[2mms[22m[39m
|
|
12
|
+
[90mstdout[2m | test/mcp.test.ts[2m > [22m[2mmcp bridge protocol transports[2m > [22m[2mdiscovers and calls tools over streamable HTTP[22m[39m
|
|
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
|
+
[90mstdout[2m | test/mcp.test.ts[2m > [22m[2mmcp bridge protocol transports[2m > [22m[2mselects discovered tools by requested patterns[22m[39m
|
|
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
|
+
[32m✓[39m test/agent-parser.test.ts [2m ([22m[2m10 tests[22m[2m)[22m[90m 24[2mms[22m[39m
|
|
22
|
+
[90mstdout[2m | test/mcp.test.ts[2m > [22m[2mmcp bridge protocol transports[2m > [22m[2mskips discovery when bearer token env value is missing[22m[39m
|
|
23
|
+
[poncho][mcp] {"event":"tools.selected","requestedPatternCount":1,"registeredCount":0,"filteredByPolicyCount":0,"filteredByIntentCount":0}
|
|
24
|
+
|
|
25
|
+
[90mstderr[2m | test/mcp.test.ts[2m > [22m[2mmcp bridge protocol transports[2m > [22m[2mskips discovery when bearer token env value is missing[22m[39m
|
|
26
|
+
[poncho][mcp] {"event":"auth.token_missing","server":"remote","tokenEnv":"MISSING_TOKEN_ENV"}
|
|
27
|
+
|
|
28
|
+
[90mstdout[2m | test/mcp.test.ts[2m > [22m[2mmcp bridge protocol transports[2m > [22m[2mreturns actionable errors for 403 permission failures[22m[39m
|
|
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
|
+
[32m✓[39m test/mcp.test.ts [2m ([22m[2m6 tests[22m[2m)[22m[90m 81[2mms[22m[39m
|
|
33
|
+
[32m✓[39m test/memory.test.ts [2m ([22m[2m4 tests[22m[2m)[22m[90m 56[2mms[22m[39m
|
|
34
|
+
[32m✓[39m test/state.test.ts [2m ([22m[2m5 tests[22m[2m)[22m[90m 237[2mms[22m[39m
|
|
35
|
+
[32m✓[39m test/model-factory.test.ts [2m ([22m[2m4 tests[22m[2m)[22m[90m 2[2mms[22m[39m
|
|
36
|
+
[32m✓[39m test/agent-identity.test.ts [2m ([22m[2m2 tests[22m[2m)[22m[90m 43[2mms[22m[39m
|
|
37
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mregisters default filesystem tools[22m[39m
|
|
38
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
39
|
+
|
|
40
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mdisables write_file by default in production environment[22m[39m
|
|
41
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
42
|
+
|
|
43
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mallows disabling built-in tools via poncho.config.js[22m[39m
|
|
44
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
45
|
+
|
|
46
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2msupports per-environment tool overrides[22m[39m
|
|
47
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
48
|
+
|
|
49
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2msupports per-environment tool overrides[22m[39m
|
|
50
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
51
|
+
|
|
52
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mdoes not auto-register exported tool objects from skill scripts[22m[39m
|
|
53
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
54
|
+
|
|
55
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mrefreshes skill metadata and tools in development mode[22m[39m
|
|
56
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
57
|
+
|
|
58
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mrefreshes skill metadata and tools in development mode[22m[39m
|
|
59
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"skills:changed","requestedPatterns":[]}
|
|
60
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"activate:beta","requestedPatterns":[]}
|
|
61
|
+
|
|
62
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mprunes removed active skills after refresh in development mode[22m[39m
|
|
63
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
64
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"activate:obsolete","requestedPatterns":[]}
|
|
65
|
+
|
|
66
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mprunes removed active skills after refresh in development mode[22m[39m
|
|
67
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"skills:changed","requestedPatterns":[]}
|
|
68
|
+
|
|
69
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mdoes not refresh skills outside development mode[22m[39m
|
|
70
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
71
|
+
|
|
72
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mclears active skills when skill metadata changes in development mode[22m[39m
|
|
73
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
74
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"activate:alpha","requestedPatterns":[]}
|
|
75
|
+
|
|
76
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mclears active skills when skill metadata changes in development mode[22m[39m
|
|
77
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"skills:changed","requestedPatterns":[]}
|
|
78
|
+
|
|
79
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mlists skill scripts through list_skill_scripts[22m[39m
|
|
80
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
81
|
+
|
|
82
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mruns JavaScript/TypeScript skill scripts through run_skill_script[22m[39m
|
|
83
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
84
|
+
|
|
85
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mruns AGENT-scope scripts from root scripts directory[22m[39m
|
|
86
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
87
|
+
|
|
88
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mblocks path traversal in run_skill_script[22m[39m
|
|
89
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
90
|
+
|
|
91
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mrequires allowed-tools entries for non-standard script directories[22m[39m
|
|
92
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
93
|
+
|
|
94
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mregisters MCP tools dynamically for stacked active skills and supports deactivation[22m[39m
|
|
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
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2msupports flat tool access config format[22m[39m
|
|
105
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
106
|
+
|
|
107
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mflat tool access takes priority over legacy defaults[22m[39m
|
|
108
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
109
|
+
|
|
110
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mbyEnvironment overrides flat tool access[22m[39m
|
|
111
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
112
|
+
|
|
113
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mregisterTools skips tools disabled via config[22m[39m
|
|
114
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
115
|
+
|
|
116
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mapproval access level registers the tool but marks it for approval[22m[39m
|
|
117
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
118
|
+
|
|
119
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mtools without approval config do not require approval[22m[39m
|
|
120
|
+
[poncho][mcp] {"event":"tools.cleared","reason":"initialize","requestedPatterns":[]}
|
|
121
|
+
|
|
122
|
+
[90mstdout[2m | test/harness.test.ts[2m > [22m[2magent harness[2m > [22m[2mallows in-flight MCP calls to finish after skill deactivation[22m[39m
|
|
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
|
+
[32m✓[39m test/harness.test.ts [2m ([22m[2m25 tests[22m[2m)[22m[90m 291[2mms[22m[39m
|
|
130
|
+
|
|
131
|
+
[2m Test Files [22m [1m[32m9 passed[39m[22m[90m (9)[39m
|
|
132
|
+
[2m Tests [22m [1m[32m86 passed[39m[22m[90m (86)[39m
|
|
133
|
+
[2m Start at [22m 17:47:43
|
|
134
|
+
[2m Duration [22m 1.88s[2m (transform 684ms, setup 1ms, collect 2.34s, tests 755ms, environment 2ms, prepare 1.27s)[22m
|
|
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
package/src/agent-parser.ts
CHANGED
|
@@ -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
|
);
|