@@ -32,20 +32,23 @@ Send a `thought` activity within the first few seconds of receiving a webhook:
3232== TypeScript {#typescript}
3333
3434``` typescript
35- import { PlaneClient } from ' @makeplane/plane-node-sdk' ;
35+ import { PlaneClient } from " @makeplane/plane-node-sdk" ;
3636
37- async function handleWebhook(webhook : AgentRunActivityWebhook , credentials : { bot_token: string ; workspace_slug: string }) {
37+ async function handleWebhook(
38+ webhook : AgentRunActivityWebhook ,
39+ credentials : { bot_token: string ; workspace_slug: string }
40+ ) {
3841 const planeClient = new PlaneClient ({
39- baseUrl: process .env .PLANE_API_URL || ' https://api.plane.so' ,
42+ baseUrl: process .env .PLANE_API_URL || " https://api.plane.so" ,
4043 accessToken: credentials .bot_token ,
4144 });
4245
4346 const agentRunId = webhook .agent_run .id ;
4447
4548 // IMMEDIATELY acknowledge receipt
4649 await planeClient .agentRuns .activities .create (credentials .workspace_slug , agentRunId , {
47- type: ' thought' ,
48- content: { type: ' thought' , body: ' Received your request. Analyzing...' },
50+ type: " thought" ,
51+ content: { type: " thought" , body: " Received your request. Analyzing..." },
4952 });
5053
5154 // Now proceed with actual processing
@@ -85,6 +88,7 @@ def handle_webhook(webhook: dict, credentials: dict):
8588
8689 # ... rest of the logic
8790```
91+
8892:::
8993
9094### Thought activity best practices
@@ -94,13 +98,15 @@ def handle_webhook(webhook: dict, credentials: dict):
9498- Use thoughts to explain what the agent is doing, not technical details
9599
96100** Good examples:**
101+
97102- "Analyzing your question about project timelines..."
98103- "Searching for relevant work items..."
99104- "Preparing response with the requested data..."
100105
101106** Avoid:**
107+
102108- "Initializing LLM context with temperature 0.7..."
103- - "Executing database query SELECT * FROM..."
109+ - "Executing database query SELECT \ * FROM..."
104110- Generic messages like "Working..." repeated multiple times
105111
106112## Acknowledging important signals
@@ -119,25 +125,28 @@ When a user wants to stop an agent run, Plane sends a `stop` signal with the act
119125== TypeScript {#typescript}
120126
121127``` typescript
122- async function handleWebhook(webhook : AgentRunActivityWebhook , credentials : { bot_token: string ; workspace_slug: string }) {
128+ async function handleWebhook(
129+ webhook : AgentRunActivityWebhook ,
130+ credentials : { bot_token: string ; workspace_slug: string }
131+ ) {
123132 const planeClient = new PlaneClient ({
124- baseUrl: process .env .PLANE_API_URL || ' https://api.plane.so' ,
133+ baseUrl: process .env .PLANE_API_URL || " https://api.plane.so" ,
125134 accessToken: credentials .bot_token ,
126135 });
127136
128137 const signal = webhook .agent_run_activity .signal ;
129138 const agentRunId = webhook .agent_run .id ;
130139
131140 // ALWAYS check for stop signal first
132- if (signal === ' stop' ) {
141+ if (signal === " stop" ) {
133142 // Cancel any ongoing work
134143 cancelOngoingTasks (agentRunId );
135144
136145 // Acknowledge the stop
137146 await planeClient .agentRuns .activities .create (credentials .workspace_slug , agentRunId , {
138- type: ' response' ,
147+ type: " response" ,
139148 content: {
140- type: ' response' ,
149+ type: " response" ,
141150 body: " Understood. I've stopped processing your previous request." ,
142151 },
143152 });
@@ -183,14 +192,15 @@ def handle_webhook(webhook: dict, credentials: dict):
183192
184193 # Continue with normal processing...
185194```
195+
186196:::
187197
188198### Signal considerations
189199
190- | Signal | How to Handle |
191- | --------| ---------------|
200+ | Signal | How to Handle |
201+ | ---------- | ----------------------------------------- |
192202| ` continue ` | Default behavior, proceed with processing |
193- | ` stop ` | Immediately halt and confirm |
203+ | ` stop ` | Immediately halt and confirm |
194204
195205## Progress communication
196206
@@ -235,34 +245,36 @@ Graceful error handling is crucial for a good user experience.
235245### Always catch and report errors
236246
237247``` typescript
238- async function handleWebhook(webhook : AgentRunActivityWebhook , credentials : { bot_token: string ; workspace_slug: string }) {
248+ async function handleWebhook(
249+ webhook : AgentRunActivityWebhook ,
250+ credentials : { bot_token: string ; workspace_slug: string }
251+ ) {
239252 const planeClient = new PlaneClient ({
240- baseUrl: process .env .PLANE_API_URL || ' https://api.plane.so' ,
253+ baseUrl: process .env .PLANE_API_URL || " https://api.plane.so" ,
241254 accessToken: credentials .bot_token ,
242255 });
243256
244257 const agentRunId = webhook .agent_run .id ;
245258
246259 try {
247260 await planeClient .agentRuns .activities .create (credentials .workspace_slug , agentRunId , {
248- type: ' thought' ,
249- content: { type: ' thought' , body: ' Processing your request...' },
261+ type: " thought" ,
262+ content: { type: " thought" , body: " Processing your request..." },
250263 });
251264
252265 // Your logic here...
253266 const result = await processRequest (webhook );
254267
255268 await planeClient .agentRuns .activities .create (credentials .workspace_slug , agentRunId , {
256- type: ' response' ,
257- content: { type: ' response' , body: result },
269+ type: " response" ,
270+ content: { type: " response" , body: result },
258271 });
259-
260272 } catch (error ) {
261273 // ALWAYS inform the user about errors
262274 await planeClient .agentRuns .activities .create (credentials .workspace_slug , agentRunId , {
263- type: ' error' ,
275+ type: " error" ,
264276 content: {
265- type: ' error' ,
277+ type: " error" ,
266278 body: getUserFriendlyErrorMessage (error ),
267279 },
268280 });
@@ -271,25 +283,27 @@ async function handleWebhook(webhook: AgentRunActivityWebhook, credentials: { bo
271283
272284function getUserFriendlyErrorMessage(error : Error ): string {
273285 // Map technical errors to user-friendly messages
274- if (error .message .includes (' rate limit' )) {
286+ if (error .message .includes (" rate limit" )) {
275287 return " I'm receiving too many requests right now. Please try again in a few minutes." ;
276288 }
277- if (error .message .includes (' timeout' )) {
278- return ' The operation took too long. Please try a simpler request or try again later.' ;
289+ if (error .message .includes (" timeout" )) {
290+ return " The operation took too long. Please try a simpler request or try again later." ;
279291 }
280292 // Generic fallback
281- return ' I encountered an unexpected error. Please try again or contact support if the issue persists.' ;
293+ return " I encountered an unexpected error. Please try again or contact support if the issue persists." ;
282294}
283295```
284296
285297### Error message guidelines
286298
287299** Do:**
300+
288301- Use clear, non-technical language
289302- Suggest next steps when possible
290303- Be honest about what went wrong (at a high level)
291304
292305** Don't:**
306+
293307- Expose stack traces or technical details
294308- Blame the user for errors
295309- Leave users without any feedback
@@ -302,16 +316,13 @@ For multi-turn conversations, maintain context from previous activities.
302316
303317``` typescript
304318// Get all activities for context
305- const activities = await planeClient .agentRuns .activities .list (
306- credentials .workspace_slug ,
307- agentRunId
308- );
319+ const activities = await planeClient .agentRuns .activities .list (credentials .workspace_slug , agentRunId );
309320
310321// Build conversation history
311322const history = activities .results
312- .filter (a => a .type === ' prompt' || a .type === ' response' )
313- .map (a => ({
314- role: a .type === ' prompt' ? ' user' : ' assistant' ,
323+ .filter (( a ) => a .type === " prompt" || a .type === " response" )
324+ .map (( a ) => ({
325+ role: a .type === " prompt" ? " user" : " assistant" ,
315326 content: a .content .body ,
316327 }));
317328
@@ -370,21 +381,25 @@ app.post("/webhook", async (req, res) => {
370381## Summary checklist
371382
372383** Responsiveness**
384+
373385- Send thought within seconds of webhook
374386- Return webhook response quickly
375387- Send heartbeats for long operations
376388
377389** Signal handling**
390+
378391- Always check for ` stop ` signal first
379392- Handle all signal types appropriately
380393- Confirm when stopping
381394
382395** Error handling**
396+
383397- Wrap processing in try/catch
384398- Always send error activity on failure
385399- Use friendly error messages
386400
387401** User experience**
402+
388403- Progress updates for long tasks
389404- Clear, non-technical communication
390405- Maintain conversation context
0 commit comments