@friendlyrobot/discord-pi-agent 0.9.3 → 0.9.5

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.
Files changed (2) hide show
  1. package/dist/index.js +43 -61
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -101,6 +101,7 @@ async function collectReply(session, prompt, options = {}) {
101
101
  let toolCount = 0;
102
102
  let sawAgentEnd = false;
103
103
  const model = session.model ? `${session.model.provider}/${session.model.id}` : "none";
104
+ console.info(prompt);
104
105
  logger3.debug({
105
106
  logPrefix,
106
107
  promptLength: prompt.length,
@@ -148,34 +149,16 @@ async function collectReply(session, prompt, options = {}) {
148
149
  const errorMessage = session.agent.state.errorMessage?.trim();
149
150
  const fallbackText = getLatestAssistantText(session.messages);
150
151
  const finalText = streamedText.trim() || fallbackText.trim();
151
- logger3.debug({
152
- eventCount,
153
- toolCount,
154
- sawAgentEnd,
155
- streamedTextLength: streamedText.trim().length,
156
- fallbackTextLength: fallbackText.trim().length,
157
- errorMessage,
158
- model,
159
- logPrefix
160
- }, "prompt done");
161
152
  if (errorMessage) {
162
153
  return errorMessage;
163
154
  }
164
155
  if (finalText) {
165
156
  const transformed = await transformMarkdownTablesToCodeBlocks(finalText);
166
- console.info(`========== reply-buffer BEFORE (${finalText.length} chars) ==========
167
- ${finalText}
168
- ========== reply-buffer BEFORE END ==========`);
169
- console.info(`========== reply-buffer AFTER (${transformed.length} chars) ==========
170
- ${transformed}
171
- ========== reply-buffer AFTER END ==========`);
172
- logger3.debug({
173
- logPrefix,
174
- model,
175
- finalTextLength: finalText.length,
176
- transformedTextLength: transformed.length,
177
- transformed: transformed !== finalText
178
- }, "assistant text ready");
157
+ console.info(`========== BEFORE ==========`);
158
+ console.info(finalText);
159
+ console.info(`========== TRANSFORMED ==========`);
160
+ console.info(transformed);
161
+ console.info(`========== END ==========`);
179
162
  return transformed;
180
163
  }
181
164
  return "No response generated.";
@@ -973,7 +956,6 @@ async function removeWorkingReaction(message) {
973
956
  var TYPING_INTERVAL_MS = 9000;
974
957
  var typingIntervals = new Map;
975
958
  async function sendTypingSafe(channel, channelKey) {
976
- logger5.info({ channelKey }, "[TYPING] calling sendTyping()");
977
959
  try {
978
960
  const token = channel.client.token;
979
961
  const url = `https://discord.com/api/v10/channels/${channel.id}/typing`;
@@ -981,23 +963,41 @@ async function sendTypingSafe(channel, channelKey) {
981
963
  method: "POST",
982
964
  headers: { Authorization: `Bot ${token}` }
983
965
  });
984
- const body = await res.text();
985
- logger5.info({ channelKey, status: res.status, headers: Object.fromEntries(res.headers.entries()), body }, "[TYPING] raw fetch response");
986
966
  if (res.ok) {
987
- logger5.info({ channelKey }, "[TYPING] raw fetch OK — Discord accepted typing");
967
+ logger5.debug({ channelKey }, "[TYPING] OK");
968
+ return;
988
969
  }
970
+ if (res.status === 429) {
971
+ const body = await res.text();
972
+ let retryMs = 3000;
973
+ try {
974
+ const parsed = JSON.parse(body);
975
+ if (typeof parsed.retry_after === "number") {
976
+ retryMs = parsed.retry_after * 1000 + 500;
977
+ }
978
+ } catch {}
979
+ logger5.warn({ channelKey, retryMs }, "[TYPING] 429, retrying after delay");
980
+ await new Promise((resolve) => setTimeout(resolve, retryMs));
981
+ await fetch(url, {
982
+ method: "POST",
983
+ headers: { Authorization: `Bot ${token}` }
984
+ });
985
+ logger5.info({ channelKey }, "[TYPING] retry done");
986
+ return;
987
+ }
988
+ logger5.warn({ channelKey, status: res.status }, "[TYPING] unexpected status");
989
989
  } catch (error) {
990
- logger5.warn({ channelKey, error }, "[TYPING] sendTyping() FAILED");
990
+ logger5.warn({ channelKey, error }, "[TYPING] FAILED");
991
991
  }
992
992
  }
993
993
  function startTypingForChannel(channel, channelKey) {
994
994
  const existing = typingIntervals.get(channelKey);
995
995
  if (existing) {
996
996
  existing.refs += 1;
997
- logger5.info({ channelKey, refs: existing.refs }, "[TYPING] ref++ (reusing existing interval)");
997
+ logger5.debug({ channelKey, refs: existing.refs }, "[TYPING] ref++ (reusing existing interval)");
998
998
  return;
999
999
  }
1000
- logger5.info({ channelKey }, "[TYPING] started new interval");
1000
+ logger5.debug({ channelKey }, "[TYPING] started new interval");
1001
1001
  sendTypingSafe(channel, channelKey);
1002
1002
  const interval = setInterval(() => {
1003
1003
  sendTypingSafe(channel, channelKey);
@@ -1007,16 +1007,16 @@ function startTypingForChannel(channel, channelKey) {
1007
1007
  function stopTypingForChannel(channelKey) {
1008
1008
  const entry = typingIntervals.get(channelKey);
1009
1009
  if (!entry) {
1010
- logger5.info({ channelKey }, "[TYPING] stop called but no entry found");
1010
+ logger5.debug({ channelKey }, "[TYPING] stop called but no entry found");
1011
1011
  return;
1012
1012
  }
1013
1013
  entry.refs -= 1;
1014
1014
  if (entry.refs <= 0) {
1015
1015
  clearInterval(entry.interval);
1016
1016
  typingIntervals.delete(channelKey);
1017
- logger5.info({ channelKey }, "[TYPING] interval cleared (refs hit 0)");
1017
+ logger5.debug({ channelKey }, "[TYPING] interval cleared (refs hit 0)");
1018
1018
  } else {
1019
- logger5.info({ channelKey, refs: entry.refs }, "[TYPING] ref-- (interval still active)");
1019
+ logger5.debug({ channelKey, refs: entry.refs }, "[TYPING] ref-- (interval still active)");
1020
1020
  }
1021
1021
  }
1022
1022
  async function sendReply(message, text) {
@@ -1028,21 +1028,20 @@ async function sendReply(message, text) {
1028
1028
  return;
1029
1029
  }
1030
1030
  const chunks = chunkMessage(text);
1031
- logger5.debug({
1032
- direction: "OUT",
1033
- messageId: message.id,
1034
- chunkCount: chunks.length,
1035
- textLength: text.length
1036
- }, "sending reply");
1031
+ logger5.debug("sending reply");
1037
1032
  const [firstChunk, ...remainingChunks] = chunks;
1038
1033
  if (!firstChunk) {
1039
1034
  return;
1040
1035
  }
1041
1036
  try {
1037
+ console.info("=== Reply Start ===");
1042
1038
  await message.reply(firstChunk);
1039
+ console.info(firstChunk);
1043
1040
  for (const chunk of remainingChunks) {
1041
+ console.info(chunk);
1044
1042
  await channel.send(chunk);
1045
1043
  }
1044
+ console.info("=== Reply End ===");
1046
1045
  } catch (error) {
1047
1046
  logger5.error({
1048
1047
  messageId: message.id,
@@ -1130,6 +1129,11 @@ async function onMessage(message, config, agentService, sessionRegistry, authCon
1130
1129
  channelType: message.channel.type,
1131
1130
  content
1132
1131
  }, "message received");
1132
+ const channelKey = message.channel.id;
1133
+ const canSend = message.channel.isSendable();
1134
+ if (canSend) {
1135
+ startTypingForChannel(message.channel, channelKey);
1136
+ }
1133
1137
  const { entry, created } = await sessionRegistry.getOrCreate(scope);
1134
1138
  const { session, promptQueue } = entry;
1135
1139
  if (created && scope.startsWith("thread:") && message.channel.isThread()) {
@@ -1138,13 +1142,6 @@ async function onMessage(message, config, agentService, sessionRegistry, authCon
1138
1142
  threadName: message.channel.name
1139
1143
  }, "new thread session");
1140
1144
  }
1141
- const channelKey = message.channel.id;
1142
- const canSend = message.channel.isSendable();
1143
- logger5.info({ channelKey, scope, canSend, channelType: message.channel.type }, "[TYPING] checking sendable");
1144
- if (canSend) {
1145
- startTypingForChannel(message.channel, channelKey);
1146
- logger5.info({ channelKey, scope }, "[TYPING] interval requested");
1147
- }
1148
1145
  const commandResult = await handleCommand(content, {
1149
1146
  agentService,
1150
1147
  promptQueue,
@@ -1185,11 +1182,6 @@ async function onMessage(message, config, agentService, sessionRegistry, authCon
1185
1182
  }
1186
1183
  await addWorkingReaction(message);
1187
1184
  const queuePosition = promptQueue.getSnapshot().pending;
1188
- logger5.debug({
1189
- scope,
1190
- messageId: message.id,
1191
- queuePosition
1192
- }, "enqueue request");
1193
1185
  if (queuePosition > 0) {
1194
1186
  await sendReply(message, `Queued. ${queuePosition} request(s) ahead of this one.`);
1195
1187
  }
@@ -1200,26 +1192,16 @@ async function onMessage(message, config, agentService, sessionRegistry, authCon
1200
1192
  messageId: message.id,
1201
1193
  scope
1202
1194
  }, "processing message");
1203
- logger5.info({ messageId: message.id, scope, channelKey }, "[TYPING] prompt enqueued, starting processing");
1204
1195
  const promptContent = buildDiscordPromptContent(message, scope, content, config);
1205
1196
  const transformedPrompt = await config.promptTransform(promptContent);
1206
- logger5.info({ messageId: message.id, scope, channelKey }, "[TYPING] about to call collectReply/session.prompt");
1207
1197
  return collectReply(session, transformedPrompt, {
1208
1198
  logPrefix: `[agent:${session.sessionId}]`
1209
1199
  });
1210
1200
  });
1211
1201
  } finally {
1212
1202
  stopTypingForChannel(channelKey);
1213
- logger5.info({ channelKey, scope }, "[TYPING] interval released");
1214
1203
  await removeWorkingReaction(message);
1215
1204
  }
1216
- logger5.info({
1217
- direction: "OUT",
1218
- scope,
1219
- messageId: message.id,
1220
- responseLength: response.length,
1221
- response
1222
- }, "response ready");
1223
1205
  await sendReply(message, response);
1224
1206
  }
1225
1207
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@friendlyrobot/discord-pi-agent",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "description": "Reusable Discord gateway bridge for persistent pi agent sessions",
5
5
  "license": "MIT",
6
6
  "type": "module",