hilos-agent 0.1.8 → 0.1.9

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/package.json +1 -1
  2. package/src/handler.mjs +33 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hilos-agent",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Run your own coding agent (Claude Code / Codex / Cursor) as an autonomous teammate in a hilos channel. Picks up @mentions in channels and threads, makes the change, and opens a PR for review — your code and credentials never leave your machine. (Approve-before-push is available via gate:true.)",
5
5
  "type": "module",
6
6
  "bin": {
package/src/handler.mjs CHANGED
@@ -226,6 +226,28 @@ export function agentProposedWork(rows, agentName) {
226
226
  );
227
227
  }
228
228
 
229
+ /**
230
+ * The task text handed to the coding CLI. The mention is always the instruction,
231
+ * but it's almost never self-contained: a reply like "yeah, do it" only means
232
+ * something against what was just said, and even a direct request is clearer with
233
+ * the surrounding discussion. So we ALWAYS prepend the recent conversation when we
234
+ * have it — the same context the chat path already gets. Falls back to the bare
235
+ * mention only when there's no transcript at all.
236
+ */
237
+ export function codeTaskPrompt({ message, context }) {
238
+ const body = String(message?.body || "").trim();
239
+ const transcript = context?.transcript?.trim();
240
+ if (!transcript) return body;
241
+ return (
242
+ `You're acting on a request in a team chat. Recent conversation (oldest first):\n` +
243
+ `${transcript}\n\n` +
244
+ `The latest message is your instruction: "${body}". Do what it asks, using the ` +
245
+ `conversation above for context — it often carries the actual spec (e.g. a reply ` +
246
+ `like "go for it" refers to what was just discussed). Make the change directly; ` +
247
+ `it will be opened as a PR for review.`
248
+ );
249
+ }
250
+
229
251
  /** owner/name from a GitHub remote URL (https or ssh), or null. */
230
252
  export function normalizeRemote(url) {
231
253
  const m = String(url || "")
@@ -393,16 +415,20 @@ export async function handleTask({ message, channelId, tool, me, caps = {} }, cf
393
415
  const { memory: workspaceMemory = null } = await tool("get_workspace_memory", {}).catch(() => ({
394
416
  memory: null,
395
417
  }));
418
+ // The conversation the agent is replying within — fetched ONCE and handed to
419
+ // BOTH the chat reply and the coding prompt. Context is always crucial: a reply
420
+ // like "yeah, do it" only means something against what was just said, and even
421
+ // a direct request is clearer with the surrounding discussion. The chat path
422
+ // always had this; the code path used to run on the bare mention alone (so
423
+ // "go for it" reached the agent with no spec → nothing built). Now both share it.
424
+ const context = await fetchContext({ channelId, tool, parentId });
396
425
  // Chat vs code. A clear action verb → code. With a repo linked, a bare
397
426
  // affirmation ("go", "ship it") that follows a plan the agent just proposed
398
427
  // ALSO means "execute it" → code path. Otherwise (greeting/question/no repo) →
399
- // a conversational reply. We fetch context once here and hand it to the chat
400
- // reply so it isn't fetched twice.
428
+ // a conversational reply.
401
429
  let isCode = looksLikeCodeTask(message.body);
402
- let context = null;
403
- if (!isCode && repoLink && isAffirmation(message.body)) {
404
- context = await fetchContext({ channelId, tool, parentId });
405
- if (agentProposedWork(context.rows, me?.agentName)) isCode = true;
430
+ if (!isCode && repoLink && isAffirmation(message.body) && agentProposedWork(context.rows, me?.agentName)) {
431
+ isCode = true;
406
432
  }
407
433
  if (!repoLink || !isCode) {
408
434
  await respondConversationally({ message, channelId, tool, me, cfg, repoLink, parentId, workspaceMemory, signal, context, caps });
@@ -630,7 +656,7 @@ export async function handleTask({ message, channelId, tool, me, caps = {} }, cf
630
656
  return { status: "cancelled", branch };
631
657
  };
632
658
 
633
- const staged = await runAndStage(message.body);
659
+ const staged = await runAndStage(codeTaskPrompt({ message, context }));
634
660
  if (staged.aborted) return await postStopped();
635
661
  if (staged.empty) {
636
662
  let body;