@parall/parel-channel 1.57.1 → 1.57.2

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.
@@ -36,8 +36,12 @@ export interface ChatPromptArgs {
36
36
  chatId: string;
37
37
  /** Display name of the chat; undefined when unresolved (best-effort). */
38
38
  chatName?: string;
39
- /** Sender user id (usr_); display-name enrichment is a follow-up. */
39
+ /** Sender user id (usr_). */
40
40
  senderId?: string;
41
+ /** Sender display name; rendered before the id when resolved (best-effort). */
42
+ senderName?: string;
43
+ /** Chat shape (direct/group); the type segment is omitted when unresolved. */
44
+ chatType?: string;
41
45
  /**
42
46
  * The inbound message id (msg_); anchors the forwarded-message hint's
43
47
  * explicit --from so coalesced turns don't lean on the single trigger id.
@@ -1 +1 @@
1
- {"version":3,"file":"channel-prompt.d.ts","sourceRoot":"","sources":["../src/channel-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA+BH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,8FAA8F;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAmBD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAqB5D;AAED,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CA2BlE"}
1
+ {"version":3,"file":"channel-prompt.d.ts","sourceRoot":"","sources":["../src/channel-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA+BH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,8FAA8F;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAmBD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAwC5D;AAgBD,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CA2BlE"}
@@ -73,16 +73,31 @@ function attachmentLines(attachments) {
73
73
  * not re-created here.
74
74
  */
75
75
  export function buildChatPrompt(args) {
76
- const chatLabel = args.chatName
77
- ? `${sanitizeMeta(args.chatId)} ${sanitizeMeta(args.chatName)}`
78
- : sanitizeMeta(args.chatId);
79
- const lines = [`[Chat: ${chatLabel}]`];
80
- if (args.senderId)
81
- lines.push(`[From: ${sanitizeMeta(args.senderId)}]`);
76
+ // agent-core's event-format.ts message branch is the SSOT for this frame:
77
+ // same lines, same order, same send-hint. The only sanctioned deltas are
78
+ // absent-field fallbacks (no chat name → bare URI, no sender name → bare
79
+ // id, no chat type → segment omitted) — agent-core's host always has them.
80
+ const lines = [`[Event: message.new]`];
81
+ const chatUri = `prll://${args.chatId}`;
82
+ const chatLabel = args.chatName ? `"${sanitizeMeta(args.chatName)}" (${chatUri})` : chatUri;
83
+ const typeSeg = args.chatType ? ` | type: ${sanitizeMeta(args.chatType)}` : '';
84
+ lines.push(`[Chat: ${chatLabel}${typeSeg}]`);
85
+ if (args.senderId) {
86
+ lines.push(args.senderName
87
+ ? `[From: ${sanitizeMeta(args.senderName)} (prll://${args.senderId})]`
88
+ : `[From: prll://${args.senderId}]`);
89
+ }
90
+ if (args.messageId)
91
+ lines.push(`[Message ID: prll://${args.messageId}]`);
82
92
  if (args.threadRootId)
83
- lines.push(`[Thread: ${sanitizeMeta(args.threadRootId)}]`);
93
+ lines.push(`[Thread: prll://${sanitizeMeta(args.threadRootId)}]`);
84
94
  if (args.deliveryReason)
85
95
  lines.push(`[Delivery: ${sanitizeMeta(args.deliveryReason)}]`);
96
+ if (args.deliveryReason === 'watcher' && args.threadRootId) {
97
+ // agent-core's threadWatcherHint, verbatim — the cooperative nudge under
98
+ // the server's agent-loop ceiling (agent-dm-loop-prevention.md Layer 4).
99
+ lines.push(`[Hint: watcher — you were not addressed in this reply. Reply only if you add something new; otherwise run \`parall no-reply\`. If this thread is not relevant to you, or you have nothing more to contribute, run \`parall messages unwatch prll://${sanitizeMeta(args.threadRootId)}\` so later replies stop waking you.]`);
100
+ }
86
101
  if (args.noReply)
87
102
  lines.push(`[Hint: no_reply]`);
88
103
  if (isForwardedMessageBody(args.text)) {
@@ -94,7 +109,21 @@ export function buildChatPrompt(args) {
94
109
  }
95
110
  lines.push(...attachmentLines(args.attachments));
96
111
  lines.push('', args.text);
97
- return lines.join('\n');
112
+ return lines.join('\n') + chatSendHint(args);
113
+ }
114
+ /**
115
+ * agent-core's buildSendMessageHint chat branch, verbatim: every chat event
116
+ * ends with the concrete send command. The standing system prompt teaches the
117
+ * CLI-only reply contract too, but a per-event reminder is what the standard
118
+ * runtimes ship — and weak models demonstrably drop the send step without it.
119
+ */
120
+ function chatSendHint(args) {
121
+ if (args.noReply)
122
+ return '';
123
+ if (args.threadRootId) {
124
+ return `\n<system-reminder>To reply in this thread, run \`parall messages send prll://${args.chatId} --thread-root-id ${sanitizeMeta(args.threadRootId)} --text-file - <<'EOF'\` … \`EOF\` — the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
125
+ }
126
+ return `\n<system-reminder>To reply, run \`parall messages send prll://${args.chatId} --text-file - <<'EOF'\` … \`EOF\` — the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
98
127
  }
99
128
  export function buildChannelPrompt(args) {
100
129
  const providerLabel = sanitizeMeta(args.provider ?? 'external IM');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/parel-channel",
3
- "version": "1.57.1",
3
+ "version": "1.57.2",
4
4
  "description": "Parall channel plugin for the parel runtime — lets a parel agent treat Parall as a managed_ws channel (receive dispatches, reply via the Parall API)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -67,8 +67,12 @@ export interface ChatPromptArgs {
67
67
  chatId: string;
68
68
  /** Display name of the chat; undefined when unresolved (best-effort). */
69
69
  chatName?: string;
70
- /** Sender user id (usr_); display-name enrichment is a follow-up. */
70
+ /** Sender user id (usr_). */
71
71
  senderId?: string;
72
+ /** Sender display name; rendered before the id when resolved (best-effort). */
73
+ senderName?: string;
74
+ /** Chat shape (direct/group); the type segment is omitted when unresolved. */
75
+ chatType?: string;
72
76
  /**
73
77
  * The inbound message id (msg_); anchors the forwarded-message hint's
74
78
  * explicit --from so coalesced turns don't lean on the single trigger id.
@@ -113,13 +117,32 @@ function attachmentLines(attachments: PromptAttachment[] | undefined): string[]
113
117
  * not re-created here.
114
118
  */
115
119
  export function buildChatPrompt(args: ChatPromptArgs): string {
116
- const chatLabel = args.chatName
117
- ? `${sanitizeMeta(args.chatId)} ${sanitizeMeta(args.chatName)}`
118
- : sanitizeMeta(args.chatId);
119
- const lines = [`[Chat: ${chatLabel}]`];
120
- if (args.senderId) lines.push(`[From: ${sanitizeMeta(args.senderId)}]`);
121
- if (args.threadRootId) lines.push(`[Thread: ${sanitizeMeta(args.threadRootId)}]`);
120
+ // agent-core's event-format.ts message branch is the SSOT for this frame:
121
+ // same lines, same order, same send-hint. The only sanctioned deltas are
122
+ // absent-field fallbacks (no chat name → bare URI, no sender name → bare
123
+ // id, no chat type → segment omitted) — agent-core's host always has them.
124
+ const lines = [`[Event: message.new]`];
125
+ const chatUri = `prll://${args.chatId}`;
126
+ const chatLabel = args.chatName ? `"${sanitizeMeta(args.chatName)}" (${chatUri})` : chatUri;
127
+ const typeSeg = args.chatType ? ` | type: ${sanitizeMeta(args.chatType)}` : '';
128
+ lines.push(`[Chat: ${chatLabel}${typeSeg}]`);
129
+ if (args.senderId) {
130
+ lines.push(
131
+ args.senderName
132
+ ? `[From: ${sanitizeMeta(args.senderName)} (prll://${args.senderId})]`
133
+ : `[From: prll://${args.senderId}]`,
134
+ );
135
+ }
136
+ if (args.messageId) lines.push(`[Message ID: prll://${args.messageId}]`);
137
+ if (args.threadRootId) lines.push(`[Thread: prll://${sanitizeMeta(args.threadRootId)}]`);
122
138
  if (args.deliveryReason) lines.push(`[Delivery: ${sanitizeMeta(args.deliveryReason)}]`);
139
+ if (args.deliveryReason === 'watcher' && args.threadRootId) {
140
+ // agent-core's threadWatcherHint, verbatim — the cooperative nudge under
141
+ // the server's agent-loop ceiling (agent-dm-loop-prevention.md Layer 4).
142
+ lines.push(
143
+ `[Hint: watcher — you were not addressed in this reply. Reply only if you add something new; otherwise run \`parall no-reply\`. If this thread is not relevant to you, or you have nothing more to contribute, run \`parall messages unwatch prll://${sanitizeMeta(args.threadRootId)}\` so later replies stop waking you.]`,
144
+ );
145
+ }
123
146
  if (args.noReply) lines.push(`[Hint: no_reply]`);
124
147
  if (isForwardedMessageBody(args.text)) {
125
148
  // Embed the concrete --from anchor: parel snapshots one invocation
@@ -132,7 +155,21 @@ export function buildChatPrompt(args: ChatPromptArgs): string {
132
155
  }
133
156
  lines.push(...attachmentLines(args.attachments));
134
157
  lines.push('', args.text);
135
- return lines.join('\n');
158
+ return lines.join('\n') + chatSendHint(args);
159
+ }
160
+
161
+ /**
162
+ * agent-core's buildSendMessageHint chat branch, verbatim: every chat event
163
+ * ends with the concrete send command. The standing system prompt teaches the
164
+ * CLI-only reply contract too, but a per-event reminder is what the standard
165
+ * runtimes ship — and weak models demonstrably drop the send step without it.
166
+ */
167
+ function chatSendHint(args: ChatPromptArgs): string {
168
+ if (args.noReply) return '';
169
+ if (args.threadRootId) {
170
+ return `\n<system-reminder>To reply in this thread, run \`parall messages send prll://${args.chatId} --thread-root-id ${sanitizeMeta(args.threadRootId)} --text-file - <<'EOF'\` … \`EOF\` — the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
171
+ }
172
+ return `\n<system-reminder>To reply, run \`parall messages send prll://${args.chatId} --text-file - <<'EOF'\` … \`EOF\` — the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
136
173
  }
137
174
 
138
175
  export interface ChannelPromptArgs {