@skydiveai/pi-extensions 0.1.0-beta.1318 → 0.1.0-beta.1326

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.mjs +24 -12
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -3664,8 +3664,14 @@ const toolCallSummaryExtension = (pi) => {
3664
3664
  * from the origin messageId in its channel context (`resolveConversationFromApi`)
3665
3665
  * — and every run of the same conversation resolves to the same id, keeping the
3666
3666
  * shared map correctly scoped across turns. `bg_*`, the completion wake, and the
3667
- * next-session injection all filter to the resolved conversation — an agent
3668
- * never sees or is woken by a task from a different chat. Only the output log
3667
+ * next-session injection all filter by a **scope key** — the resolved
3668
+ * conversation id, or, when a session's conversation is unresolvable (a bare
3669
+ * CLI session, or a run whose channel-context ref carries no messageId), a
3670
+ * sentinel unique to that one session instance. Comparing on the raw
3671
+ * `conversationId` would bucket every unresolvable session together under
3672
+ * `null` and leak one's completion wake / status / next-session injection into
3673
+ * another; the sentinel keeps each isolated so an agent never sees or is woken
3674
+ * by a task from a different chat. Only the output log
3669
3675
  * spills to disk (/home/user/.anyone/bg-tasks/<id>.log) to avoid buffering a chatty job
3670
3676
  * in memory; exit code and run state live on the in-memory task.
3671
3677
  *
@@ -3696,11 +3702,12 @@ function taskLabel(meta) {
3696
3702
  return `${meta.id} "${meta.description ?? meta.command.slice(0, 60)}"`;
3697
3703
  }
3698
3704
  let taskCounter = 0;
3705
+ let sessionScopeCounter = 0;
3699
3706
  const tasks = /* @__PURE__ */ new Map();
3700
3707
  let watchdogInterval = null;
3701
3708
  let lastKeepaliveAt = 0;
3702
- function sameConversation(meta, conversationId) {
3703
- return meta.conversationId === conversationId;
3709
+ function sameScope(meta, scopeKey) {
3710
+ return meta.scopeKey === scopeKey;
3704
3711
  }
3705
3712
  function logPath(id) {
3706
3713
  return join(tasksDir(), `${id}.log`);
@@ -3813,6 +3820,10 @@ function createBackgroundTasksExtension({ channelContext }) {
3813
3820
  return id;
3814
3821
  });
3815
3822
  }
3823
+ const unresolvedScopeSentinel = `unresolved:${process.pid.toString(36)}:${(sessionScopeCounter += 1).toString(36)}`;
3824
+ function scopeKey() {
3825
+ return conversationId ?? unresolvedScopeSentinel;
3826
+ }
3816
3827
  let agentActive = false;
3817
3828
  pi.on("agent_start", async () => {
3818
3829
  agentActive = true;
@@ -3846,7 +3857,7 @@ This is a background-task completion, not a message from the user. If it needs n
3846
3857
  }
3847
3858
  async function notifyCompletion(meta) {
3848
3859
  if (meta.notified) return;
3849
- if (agentActive && sameConversation(meta, conversationId)) {
3860
+ if (agentActive && sameScope(meta, scopeKey())) {
3850
3861
  meta.notified = true;
3851
3862
  pi.sendMessage(await taskDoneMessage(meta), {
3852
3863
  triggerTurn: true,
@@ -3903,6 +3914,7 @@ This is a background-task completion, not a message from the user. If it needs n
3903
3914
  logBytes: 0,
3904
3915
  lastOutputAt: startedAt,
3905
3916
  conversationId,
3917
+ scopeKey: scopeKey(),
3906
3918
  messageId,
3907
3919
  description,
3908
3920
  notified: false,
@@ -3948,16 +3960,16 @@ This is a background-task completion, not a message from the user. If it needs n
3948
3960
  return meta;
3949
3961
  }
3950
3962
  function knownTaskIds() {
3951
- return [...tasks.values()].filter((t) => sameConversation(t, conversationId)).map((t) => t.id).join(", ") || "(none)";
3963
+ return [...tasks.values()].filter((t) => sameScope(t, scopeKey())).map((t) => t.id).join(", ") || "(none)";
3952
3964
  }
3953
3965
  pi.on("session_start", async () => {
3954
3966
  if (tasks.size === 0) return;
3955
3967
  await ensureConversationId();
3956
- for (const [id, meta] of tasks) if (sameConversation(meta, conversationId) && !meta.running && meta.notified) {
3968
+ for (const [id, meta] of tasks) if (sameScope(meta, scopeKey()) && !meta.running && meta.notified) {
3957
3969
  tasks.delete(id);
3958
3970
  await unlink(logPath(id)).catch(() => {});
3959
3971
  }
3960
- const unnotified = [...tasks.values()].filter((t) => sameConversation(t, conversationId) && !t.notified && !t.running);
3972
+ const unnotified = [...tasks.values()].filter((t) => sameScope(t, scopeKey()) && !t.notified && !t.running);
3961
3973
  for (const meta of unnotified) {
3962
3974
  meta.notified = true;
3963
3975
  pi.sendMessage(await taskDoneMessage(meta));
@@ -3966,7 +3978,7 @@ This is a background-task completion, not a message from the user. If it needs n
3966
3978
  conversationId,
3967
3979
  count: unnotified.length
3968
3980
  }, "injected completed bg tasks at session_start");
3969
- if ([...tasks.values()].some((t) => sameConversation(t, conversationId) && t.running)) ensureWatchdog();
3981
+ if ([...tasks.values()].some((t) => sameScope(t, scopeKey()) && t.running)) ensureWatchdog();
3970
3982
  });
3971
3983
  function err(text) {
3972
3984
  return {
@@ -3983,11 +3995,11 @@ This is a background-task completion, not a message from the user. If it needs n
3983
3995
  }
3984
3996
  function resolveTask(taskId) {
3985
3997
  const exact = tasks.get(taskId);
3986
- if (exact && sameConversation(exact, conversationId)) return {
3998
+ if (exact && sameScope(exact, scopeKey())) return {
3987
3999
  error: null,
3988
4000
  meta: exact
3989
4001
  };
3990
- const matches = [...tasks.values()].filter((t) => sameConversation(t, conversationId) && t.id.startsWith(taskId));
4002
+ const matches = [...tasks.values()].filter((t) => sameScope(t, scopeKey()) && t.id.startsWith(taskId));
3991
4003
  if (matches.length === 1) return {
3992
4004
  error: null,
3993
4005
  meta: matches[0]
@@ -3996,7 +4008,7 @@ This is a background-task completion, not a message from the user. If it needs n
3996
4008
  return err(`Unknown task ${taskId}. Known tasks: ${knownTaskIds()}`);
3997
4009
  }
3998
4010
  function listTasks() {
3999
- const mine = [...tasks.values()].filter((t) => sameConversation(t, conversationId));
4011
+ const mine = [...tasks.values()].filter((t) => sameScope(t, scopeKey()));
4000
4012
  if (mine.length === 0) return "No background tasks.";
4001
4013
  return mine.map((t) => {
4002
4014
  const state = t.running ? "running" : t.exitCode !== null ? `exited ${t.exitCode}${t.killedReason ? ` (killed: ${t.killedReason})` : ""}` : t.killedReason ? `killed: ${t.killedReason}` : "ended";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skydiveai/pi-extensions",
3
- "version": "0.1.0-beta.1318",
3
+ "version": "0.1.0-beta.1326",
4
4
  "homepage": "https://skydive.com",
5
5
  "license": "MIT",
6
6
  "author": "Create, Inc.",