patchrelay 0.55.1 → 0.56.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,6 +1,6 @@
1
1
  {
2
2
  "service": "patchrelay",
3
- "version": "0.55.1",
4
- "commit": "ec34142b31f4",
5
- "builtAt": "2026-05-01T12:38:54.375Z"
3
+ "version": "0.56.0",
4
+ "commit": "43aa8a020a26",
5
+ "builtAt": "2026-05-01T14:26:54.243Z"
6
6
  }
@@ -42,6 +42,12 @@ export function buildAlreadyRunningThought(runType) {
42
42
  body: `PatchRelay is already working on the ${lowerRunTypeLabel(runType)} workflow.`,
43
43
  };
44
44
  }
45
+ export function buildAgentSessionAcknowledgementThought() {
46
+ return {
47
+ type: "thought",
48
+ body: "PatchRelay received this agent session and is checking the issue state.",
49
+ };
50
+ }
45
51
  export function buildBlockedDelegationActivity(blockedByKeys = []) {
46
52
  const blockers = blockedByKeys.filter((key) => key.trim().length > 0);
47
53
  const blockerText = blockers.length > 0
@@ -74,6 +74,7 @@ export class WebhookHandler {
74
74
  this.db.webhookEvents.markWebhookProcessed(webhookEventId, "processed");
75
75
  return;
76
76
  }
77
+ await this.agentSessionHandler.acknowledgeCreated(normalized);
77
78
  const routed = await this.contextLoader.load(normalized);
78
79
  const project = routed?.project;
79
80
  if (!project) {
@@ -1,7 +1,14 @@
1
1
  import { buildAgentSessionPlanForIssue, } from "../agent-session-plan.js";
2
2
  import { buildAgentSessionExternalUrls } from "../agent-session-presentation.js";
3
- import { buildAlreadyRunningThought, buildBlockedDelegationActivity, buildDelegationThought, buildPromptDeliveredThought, buildStopConfirmationActivity, } from "../linear-session-reporting.js";
4
- import { triggerEventAllowed } from "../project-resolution.js";
3
+ import { buildAlreadyRunningThought, buildAgentSessionAcknowledgementThought, buildBlockedDelegationActivity, buildDelegationThought, buildPromptDeliveredThought, buildStopConfirmationActivity, } from "../linear-session-reporting.js";
4
+ import { resolveProject, triggerEventAllowed } from "../project-resolution.js";
5
+ const PATCHRELAY_AGENT_ACTIVITY_TYPES = new Set([
6
+ "action",
7
+ "elicitation",
8
+ "error",
9
+ "response",
10
+ "thought",
11
+ ]);
5
12
  export class AgentSessionHandler {
6
13
  config;
7
14
  db;
@@ -17,6 +24,33 @@ export class AgentSessionHandler {
17
24
  this.logger = logger;
18
25
  this.feed = feed;
19
26
  }
27
+ async acknowledgeCreated(normalized) {
28
+ if (normalized.triggerEvent !== "agentSessionCreated" || !normalized.agentSession?.id || !normalized.issue) {
29
+ return;
30
+ }
31
+ const project = resolveProject(this.config, normalized.issue);
32
+ if (!project || !triggerEventAllowed(project, normalized.triggerEvent)) {
33
+ return;
34
+ }
35
+ const linear = await this.linearProvider.forProject(project.id);
36
+ if (!linear?.createAgentActivity) {
37
+ return;
38
+ }
39
+ try {
40
+ await linear.createAgentActivity({
41
+ agentSessionId: normalized.agentSession.id,
42
+ content: buildAgentSessionAcknowledgementThought(),
43
+ ephemeral: true,
44
+ });
45
+ }
46
+ catch (error) {
47
+ this.logger.warn({
48
+ agentSessionId: normalized.agentSession.id,
49
+ issueKey: normalized.issue.identifier,
50
+ error: error instanceof Error ? error.message : String(error),
51
+ }, "Failed to acknowledge Linear agent session creation");
52
+ }
53
+ }
20
54
  async handle(params) {
21
55
  const { normalized, project, trackedIssue, wakeRunType, delegated } = params;
22
56
  if (!normalized.agentSession?.id || !normalized.issue)
@@ -76,6 +110,17 @@ export class AgentSessionHandler {
76
110
  return;
77
111
  if (!triggerEventAllowed(project, normalized.triggerEvent))
78
112
  return;
113
+ if (isPatchRelayAgentActivityEcho(normalized.agentSession)) {
114
+ this.feed?.publish({
115
+ level: "info",
116
+ kind: "agent",
117
+ projectId: project.id,
118
+ issueKey: trackedIssue?.issueKey,
119
+ status: "ignored_echo",
120
+ summary: `Ignored Linear agent activity echo (${normalized.agentSession.activityType})`,
121
+ });
122
+ return;
123
+ }
79
124
  const promptBody = normalized.agentSession.promptBody?.trim();
80
125
  if (!automationEnabled && promptBody && existingIssue) {
81
126
  await this.publishAgentActivity(linear, normalized.agentSession.id, {
@@ -223,3 +268,7 @@ export class AgentSessionHandler {
223
268
  }
224
269
  }
225
270
  }
271
+ function isPatchRelayAgentActivityEcho(agentSession) {
272
+ const activityType = agentSession?.activityType?.trim().toLowerCase();
273
+ return Boolean(activityType && PATCHRELAY_AGENT_ACTIVITY_TYPES.has(activityType));
274
+ }
package/dist/webhooks.js CHANGED
@@ -55,7 +55,8 @@ function deriveTriggerEvent(payload) {
55
55
  ["payload", "agentActivity"],
56
56
  ["resource", "agentActivity"],
57
57
  ]);
58
- if (agentActivityForSignal && getString(agentActivityForSignal, "signal")) {
58
+ const agentActivityContent = asRecord(agentActivityForSignal?.content);
59
+ if (agentActivityForSignal && (getString(agentActivityForSignal, "signal") || getString(agentActivityContent ?? {}, "signal"))) {
59
60
  return "agentSignal";
60
61
  }
61
62
  if (payload.action === "created" || payload.action === "create") {
@@ -331,6 +332,8 @@ function extractAgentSessionMetadata(payload) {
331
332
  ["payload", "agentActivity"],
332
333
  ["resource", "agentActivity"],
333
334
  ]);
335
+ const agentActivityRecord = agentActivity ?? {};
336
+ const agentActivityContent = asRecord(agentActivityRecord.content) ?? {};
334
337
  const commentRecord = getFirstNestedRecord(data, [
335
338
  ["comment"],
336
339
  ["agentSession", "comment"],
@@ -341,17 +344,23 @@ function extractAgentSessionMetadata(payload) {
341
344
  ]) ??
342
345
  getFirstNestedRecord(sessionRecord, [["comment"]]);
343
346
  const promptContext = getString(data, "promptContext") ?? getString(sessionRecord ?? {}, "promptContext");
344
- const promptBody = getString(agentActivity ?? {}, "body") ??
347
+ const activityId = getString(agentActivityRecord, "id");
348
+ const activityType = getString(agentActivityRecord, "type") ?? getString(agentActivityContent, "type");
349
+ const activityBody = getString(agentActivityRecord, "body") ?? getString(agentActivityContent, "body");
350
+ const promptBody = activityBody ??
345
351
  getString(commentRecord ?? {}, "body") ??
346
352
  getString(data, "body");
347
353
  const issueCommentId = getString(commentRecord ?? {}, "id") ?? getString(data, "issueCommentId");
348
- const signal = getString(agentActivity ?? {}, "signal");
349
- const signalMetadata = asRecord((agentActivity ?? {}).signalMetadata);
354
+ const signal = getString(agentActivityRecord, "signal") ?? getString(agentActivityContent, "signal");
355
+ const signalMetadata = asRecord(agentActivityRecord.signalMetadata) ?? asRecord(agentActivityContent.signalMetadata);
350
356
  return {
351
357
  id,
352
358
  ...(promptContext ? { promptContext } : {}),
353
359
  ...(promptBody ? { promptBody } : {}),
354
360
  ...(issueCommentId ? { issueCommentId } : {}),
361
+ ...(activityId ? { activityId } : {}),
362
+ ...(activityType ? { activityType } : {}),
363
+ ...(activityBody ? { activityBody } : {}),
355
364
  ...(signal ? { signal } : {}),
356
365
  ...(signalMetadata ? { signalMetadata } : {}),
357
366
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchrelay",
3
- "version": "0.55.1",
3
+ "version": "0.56.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {