@standardagents/code 0.6.6 → 0.6.7

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.
package/dist/index.js CHANGED
@@ -1916,6 +1916,90 @@ var SystemEvents = class {
1916
1916
  }
1917
1917
  };
1918
1918
 
1919
+ // src/subagent-streams.ts
1920
+ var MAX_PHRASE = 120;
1921
+ function cleanPhrase(raw) {
1922
+ const s = raw.replace(/\s+/g, " ").trim();
1923
+ return s.length > MAX_PHRASE ? `${s.slice(0, MAX_PHRASE - 1)}\u2026` : s;
1924
+ }
1925
+ function prettyToolName(name) {
1926
+ return name.replace(/^provider:/, "").replace(/[_:-]+/g, " ").trim();
1927
+ }
1928
+ var SubagentActivity = class {
1929
+ constructor(api, onChange, makeStream = (threadId, hooks) => new MessageStream(api, threadId, hooks)) {
1930
+ this.onChange = onChange;
1931
+ this.makeStream = makeStream;
1932
+ }
1933
+ onChange;
1934
+ makeStream;
1935
+ entries = /* @__PURE__ */ new Map();
1936
+ /** The current activity phrase for a subagent's child thread, if any. */
1937
+ phraseFor(threadId) {
1938
+ return this.entries.get(threadId)?.phrase ?? null;
1939
+ }
1940
+ /**
1941
+ * Reconcile the open streams against the authoritative set of RUNNING
1942
+ * subagent child-thread ids (from the parent's registry): open newcomers,
1943
+ * close and forget departed ones.
1944
+ */
1945
+ sync(activeIds) {
1946
+ const want = new Set(activeIds);
1947
+ for (const [id, entry] of [...this.entries]) {
1948
+ if (!want.has(id)) {
1949
+ entry.stream.close();
1950
+ this.entries.delete(id);
1951
+ }
1952
+ }
1953
+ for (const id of want) {
1954
+ if (!this.entries.has(id)) this.open(id);
1955
+ }
1956
+ }
1957
+ open(threadId) {
1958
+ const entry = { stream: null, steps: /* @__PURE__ */ new Map(), phrase: null };
1959
+ const setPhrase = (phrase) => {
1960
+ if (phrase === entry.phrase) return;
1961
+ entry.phrase = phrase;
1962
+ this.onChange(threadId);
1963
+ };
1964
+ const phraseFromSteps = () => {
1965
+ let last = null;
1966
+ for (const v of entry.steps.values()) last = v;
1967
+ return last ?? entry.phrase;
1968
+ };
1969
+ entry.stream = this.makeStream(threadId, {
1970
+ // Streamed output with no tool in flight means the model is composing —
1971
+ // reasoning reads as "thinking", visible answer text as "writing". These
1972
+ // only fire on TRANSITIONS (phrase comparison), not per chunk.
1973
+ onChunk: () => {
1974
+ if (entry.steps.size === 0) setPhrase("writing");
1975
+ },
1976
+ onReasoningChunk: () => {
1977
+ if (entry.steps.size === 0) setPhrase("thinking");
1978
+ },
1979
+ onAssistantText: () => {
1980
+ },
1981
+ onEvent: (eventType, data) => {
1982
+ if (eventType === "tool_call_started" && data?.id) {
1983
+ entry.steps.set(String(data.id), cleanPhrase(String(data.progress || prettyToolName(String(data.name || "")) || "working")));
1984
+ setPhrase(phraseFromSteps());
1985
+ } else if (eventType === "tool_call_done" && data?.id) {
1986
+ entry.steps.delete(String(data.id));
1987
+ setPhrase(phraseFromSteps());
1988
+ }
1989
+ },
1990
+ onError: () => {
1991
+ }
1992
+ });
1993
+ this.entries.set(threadId, entry);
1994
+ void entry.stream.connect();
1995
+ }
1996
+ /** Close every stream (session teardown). */
1997
+ closeAll() {
1998
+ for (const entry of this.entries.values()) entry.stream.close();
1999
+ this.entries.clear();
2000
+ }
2001
+ };
2002
+
1919
2003
  // src/wordmill.ts
1920
2004
  var MILL_WORDS = [
1921
2005
  "Working",
@@ -5025,8 +5109,12 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
5025
5109
  const agentTitlesReady = api.listAgents().then((list) => list.forEach((a) => agentTitles.set(a.name, a.title))).catch(() => {
5026
5110
  });
5027
5111
  const pushSubagents = () => tui.setSubagents(
5028
- [...activeSubagents.entries()].map(([id, s]) => ({ id, label: s.label, agentName: s.agentName }))
5112
+ [...activeSubagents.entries()].map(([id, s]) => {
5113
+ const detail = subActivity.phraseFor(id) ?? s.registryDetail;
5114
+ return { id, label: `${s.title}${detail ? ` \u2014 ${detail}` : ""}`, agentName: s.agentName };
5115
+ })
5029
5116
  );
5117
+ const subActivity = new SubagentActivity(api, () => pushSubagents());
5030
5118
  const reconcileSubagents = async () => {
5031
5119
  try {
5032
5120
  await agentTitlesReady;
@@ -5036,12 +5124,13 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
5036
5124
  const status = (s.status || "").trim();
5037
5125
  if (status === "idle" || status === "terminated") continue;
5038
5126
  const oneLineStatus = status.replace(/\s+/g, " ");
5039
- const detail = oneLineStatus && oneLineStatus !== "running" ? ` \u2014 ${oneLineStatus.slice(0, 80)}` : "";
5040
5127
  activeSubagents.set(s.id, {
5041
- label: `${subagentLabel(s, agentTitles)}${detail}`,
5128
+ title: subagentLabel(s, agentTitles),
5129
+ registryDetail: oneLineStatus && oneLineStatus !== "running" ? oneLineStatus.slice(0, 80) : "",
5042
5130
  agentName: s.agent_name ?? void 0
5043
5131
  });
5044
5132
  }
5133
+ subActivity.sync(activeSubagents.keys());
5045
5134
  pushSubagents();
5046
5135
  } catch {
5047
5136
  }
@@ -5088,6 +5177,7 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
5088
5177
  bridge.close();
5089
5178
  stream.close();
5090
5179
  events.close();
5180
+ subActivity.closeAll();
5091
5181
  mcp.closeAll();
5092
5182
  const [, killed2] = await Promise.race([
5093
5183
  Promise.all([stopped2, procsStopped2]),
@@ -5508,6 +5598,7 @@ ${c.bold}why: ${req.requestPermission}${c.reset}` : ""}`,
5508
5598
  bridge.close();
5509
5599
  stream.close();
5510
5600
  events.close();
5601
+ subActivity.closeAll();
5511
5602
  mcp.closeAll();
5512
5603
  const [, killed] = await Promise.race([
5513
5604
  Promise.all([stopped, procsStopped]),