@agent-team-foundation/first-tree-hub 0.10.5 → 0.10.6

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.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import "../observability-DPyf745N-BSc8QNcR.mjs";
3
- import { A as checkServerHealth, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as installClientService, G as createOwner, H as ClientRuntime, I as isServiceSupported, J as fail, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as getClientServiceStatus, Q as setJsonMode, S as runMigrations, T as checkClientConfig, U as handleClientOrgMismatch, V as stopPostgres, Y as success, Z as print, _ as onboardCreate, a as declineUpdate, at as probeCapabilities, b as createApiNameResolver, c as COMMAND_VERSION, d as isInteractive, et as ClientOrgMismatchError, f as promptAddAgent, g as onboardCheck, h as loadOnboardState, i as createExecuteUpdate, it as cleanWorkspaces, j as checkServerReachable, k as checkServerConfig, l as reconcileLocalRuntimeProviders, m as formatCheckReport, nt as SdkError, o as promptUpdate, ot as applyClientLoggerConfig, p as promptMissingFields, q as resolveReplyToFromEnv, r as registerSaaSConnectCommand, rt as SessionRegistry, s as startServer, st as configureClientLoggerForService, tt as FirstTreeHubSDK, u as uploadClientCapabilities, v as saveOnboardState, w as checkBackgroundService, x as migrateLocalAgentDirs, y as runHomeMigration } from "../saas-connect-2puW1r3r.mjs";
3
+ import { A as checkServerHealth, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as installClientService, G as createOwner, H as ClientRuntime, I as isServiceSupported, J as fail, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as getClientServiceStatus, Q as setJsonMode, S as runMigrations, T as checkClientConfig, U as handleClientOrgMismatch, V as stopPostgres, Y as success, Z as print, _ as onboardCreate, a as declineUpdate, at as probeCapabilities, b as createApiNameResolver, c as COMMAND_VERSION, d as isInteractive, et as ClientOrgMismatchError, f as promptAddAgent, g as onboardCheck, h as loadOnboardState, i as createExecuteUpdate, it as cleanWorkspaces, j as checkServerReachable, k as checkServerConfig, l as reconcileLocalRuntimeProviders, m as formatCheckReport, nt as SdkError, o as promptUpdate, ot as applyClientLoggerConfig, p as promptMissingFields, q as resolveReplyToFromEnv, r as registerSaaSConnectCommand, rt as SessionRegistry, s as startServer, st as configureClientLoggerForService, tt as FirstTreeHubSDK, u as uploadClientCapabilities, v as saveOnboardState, w as checkBackgroundService, x as migrateLocalAgentDirs, y as runHomeMigration } from "../saas-connect-vLyx73kJ.mjs";
4
4
  import "../logger-core-BTmvdflj-DjW8FM4T.mjs";
5
5
  import { C as serverConfigSchema, _ as loadAgents, b as resetConfig, c as saveCredentials, d as DEFAULT_HOME_DIR, f as agentConfigSchema, g as initConfig, h as getConfigValue, i as loadCredentials, l as DEFAULT_CONFIG_DIR, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, r as ensureFreshAdminToken, s as saveAgentConfig, u as DEFAULT_DATA_DIR, w as setConfigValue, x as resetConfigMeta, y as readConfigFile } from "../bootstrap-jx5nN1qZ.mjs";
6
6
  import "../dist-CbX9mUVH.mjs";
@@ -0,0 +1,28 @@
1
+ -- Backfill: in any direct chat with no human participant, flip both agents to
2
+ -- `mention_only`. New direct chats created by `findOrCreateDirectChat` and
3
+ -- `createChat` already encode this rule at insert time; this migration patches
4
+ -- chats created before the rule existed.
5
+ --
6
+ -- Why: `full` mode in agent↔agent direct chats causes a reply loop. Every
7
+ -- message wakes the other party unconditionally, so a courtesy "thanks" or
8
+ -- a duplicated "已回复" tool echo gets treated as a fresh prompt and the two
9
+ -- agents chat forever. `mention_only` makes engagement opt-in via `@` so
10
+ -- conversations naturally end. Human↔agent direct stays `full` because in a
11
+ -- 1:1 with a person the agent must respond on every turn — the human
12
+ -- participant is what flips the rule off.
13
+ --
14
+ -- Group chats are intentionally untouched. Existing rule
15
+ -- (`maybeUpgradeDirectToGroup`) already enforces mention_only for non-human
16
+ -- participants there.
17
+
18
+ UPDATE "chat_participants"
19
+ SET "mode" = 'mention_only'
20
+ WHERE "chat_id" IN (
21
+ SELECT c."id" FROM "chats" c
22
+ WHERE c."type" = 'direct'
23
+ AND NOT EXISTS (
24
+ SELECT 1 FROM "chat_participants" cp
25
+ INNER JOIN "agents" a ON a."uuid" = cp."agent_id"
26
+ WHERE cp."chat_id" = c."id" AND a."type" = 'human'
27
+ )
28
+ );
@@ -204,6 +204,13 @@
204
204
  "when": 1777680000000,
205
205
  "tag": "0028_auth_identity_user_github_unique",
206
206
  "breakpoints": true
207
+ },
208
+ {
209
+ "idx": 29,
210
+ "version": "7",
211
+ "when": 1777766400000,
212
+ "tag": "0029_direct_agent_only_mention_only",
213
+ "breakpoints": true
207
214
  }
208
215
  ]
209
216
  }
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./observability-DPyf745N-BSc8QNcR.mjs";
2
- import { $ as status, A as checkServerHealth, B as isDockerAvailable, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as installClientService, G as createOwner, H as ClientRuntime, I as isServiceSupported, K as hasUser, L as resolveCliInvocation, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as getClientServiceStatus, R as uninstallClientService, S as runMigrations, T as checkClientConfig, U as handleClientOrgMismatch, V as stopPostgres, W as rotateClientIdWithBackup, X as blank, _ as onboardCreate, d as isInteractive, f as promptAddAgent, g as onboardCheck, j as checkServerReachable, k as checkServerConfig, m as formatCheckReport, n as deriveHubUrlFromToken, nt as SdkError, p as promptMissingFields, s as startServer, t as HubUrlDerivationError, tt as FirstTreeHubSDK, y as runHomeMigration, z as ensurePostgres } from "./saas-connect-2puW1r3r.mjs";
2
+ import { $ as status, A as checkServerHealth, B as isDockerAvailable, C as checkAgentConfigs, D as checkDocker, E as checkDatabase, F as installClientService, G as createOwner, H as ClientRuntime, I as isServiceSupported, K as hasUser, L as resolveCliInvocation, M as checkWebSocket, N as printResults, O as checkNodeVersion, P as getClientServiceStatus, R as uninstallClientService, S as runMigrations, T as checkClientConfig, U as handleClientOrgMismatch, V as stopPostgres, W as rotateClientIdWithBackup, X as blank, _ as onboardCreate, d as isInteractive, f as promptAddAgent, g as onboardCheck, j as checkServerReachable, k as checkServerConfig, m as formatCheckReport, n as deriveHubUrlFromToken, nt as SdkError, p as promptMissingFields, s as startServer, t as HubUrlDerivationError, tt as FirstTreeHubSDK, y as runHomeMigration, z as ensurePostgres } from "./saas-connect-vLyx73kJ.mjs";
3
3
  import "./logger-core-BTmvdflj-DjW8FM4T.mjs";
4
4
  import { a as resolveAccessToken, n as ensureFreshAccessToken, o as resolveServerUrl, r as ensureFreshAdminToken } from "./bootstrap-jx5nN1qZ.mjs";
5
5
  import "./dist-CbX9mUVH.mjs";
@@ -4483,7 +4483,11 @@ var Deduplicator = class {
4483
4483
  function createResultSink(deps) {
4484
4484
  async function buildMetadata(trigger) {
4485
4485
  if (!trigger || trigger.senderId === deps.agent.agentId) return void 0;
4486
- if ((await deps.participants.get()).length <= 2) return void 0;
4486
+ const participants = await deps.participants.get();
4487
+ if (participants.length <= 2) {
4488
+ const peer = participants.find((p) => p.agentId === trigger.senderId);
4489
+ if (peer && peer.mode !== "mention_only") return void 0;
4490
+ }
4487
4491
  return { mentions: [trigger.senderId] };
4488
4492
  }
4489
4493
  return async function forwardResult(text) {
@@ -8532,7 +8536,7 @@ function createFeedbackHandler(config) {
8532
8536
  return { handle };
8533
8537
  }
8534
8538
  //#endregion
8535
- //#region ../server/dist/app-fbgPnPWI.mjs
8539
+ //#region ../server/dist/app-Ed9CsDC-.mjs
8536
8540
  var __defProp = Object.defineProperty;
8537
8541
  var __exportAll = (all, no_symbols) => {
8538
8542
  let target = {};
@@ -8943,15 +8947,18 @@ async function findOrCreateChatForChannel(db, data) {
8943
8947
  const participants = data.botAgentId === data.senderAgentId ? [{
8944
8948
  chatId,
8945
8949
  agentId: data.botAgentId,
8946
- role: "member"
8950
+ role: "member",
8951
+ mode: "full"
8947
8952
  }] : [{
8948
8953
  chatId,
8949
8954
  agentId: data.botAgentId,
8950
- role: "member"
8955
+ role: "member",
8956
+ mode: "full"
8951
8957
  }, {
8952
8958
  chatId,
8953
8959
  agentId: data.senderAgentId,
8954
- role: "member"
8960
+ role: "member",
8961
+ mode: "full"
8955
8962
  }];
8956
8963
  await tx.insert(chatParticipants).values(participants);
8957
8964
  await tx.insert(adapterChatMappings).values({
@@ -9832,7 +9839,8 @@ async function createChat(db, creatorId, data) {
9832
9839
  const allParticipantIds = new Set([creatorId, ...data.participantIds]);
9833
9840
  const existingAgents = await db.select({
9834
9841
  id: agents.uuid,
9835
- organizationId: agents.organizationId
9842
+ organizationId: agents.organizationId,
9843
+ type: agents.type
9836
9844
  }).from(agents).where(inArray(agents.uuid, [...allParticipantIds]));
9837
9845
  if (existingAgents.length !== allParticipantIds.size) {
9838
9846
  const found = new Set(existingAgents.map((a) => a.id));
@@ -9843,6 +9851,7 @@ async function createChat(db, creatorId, data) {
9843
9851
  const orgId = creator.organizationId;
9844
9852
  const crossOrg = existingAgents.filter((a) => a.organizationId !== orgId);
9845
9853
  if (crossOrg.length > 0) throw new BadRequestError(`Cross-organization chat not allowed: ${crossOrg.map((a) => a.id).join(", ")}`);
9854
+ const isDirectAgentOnly = data.type === "direct" && existingAgents.every((a) => a.type !== "human");
9846
9855
  return db.transaction(async (tx) => {
9847
9856
  const [chat] = await tx.insert(chats).values({
9848
9857
  id: chatId,
@@ -9854,7 +9863,8 @@ async function createChat(db, creatorId, data) {
9854
9863
  const participantRows = [...allParticipantIds].map((agentId) => ({
9855
9864
  chatId,
9856
9865
  agentId,
9857
- role: agentId === creatorId ? "owner" : "member"
9866
+ role: agentId === creatorId ? "owner" : "member",
9867
+ ...isDirectAgentOnly ? { mode: "mention_only" } : {}
9858
9868
  }));
9859
9869
  await tx.insert(chatParticipants).values(participantRows);
9860
9870
  const participants = await tx.select().from(chatParticipants).where(eq(chatParticipants.chatId, chatId));
@@ -10072,8 +10082,16 @@ async function findOrCreateDirectChat(db, agentAId, agentBId) {
10072
10082
  const directChats = await db.select().from(chats).where(and(inArray(chats.id, commonChatIds), eq(chats.type, "direct")));
10073
10083
  if (directChats.length > 0 && directChats[0]) return directChats[0];
10074
10084
  }
10075
- const [agentA] = await db.select({ organizationId: agents.organizationId }).from(agents).where(eq(agents.uuid, agentAId)).limit(1);
10085
+ const ends = await db.select({
10086
+ uuid: agents.uuid,
10087
+ organizationId: agents.organizationId,
10088
+ type: agents.type
10089
+ }).from(agents).where(inArray(agents.uuid, [agentAId, agentBId]));
10090
+ const agentA = ends.find((a) => a.uuid === agentAId);
10076
10091
  if (!agentA) throw new NotFoundError(`Agent "${agentAId}" not found`);
10092
+ const agentB = ends.find((a) => a.uuid === agentBId);
10093
+ if (!agentB) throw new NotFoundError(`Agent "${agentBId}" not found`);
10094
+ const mode = agentA.type !== "human" && agentB.type !== "human" ? "mention_only" : "full";
10077
10095
  const chatId = randomUUID();
10078
10096
  return db.transaction(async (tx) => {
10079
10097
  const [chat] = await tx.insert(chats).values({
@@ -10084,11 +10102,13 @@ async function findOrCreateDirectChat(db, agentAId, agentBId) {
10084
10102
  await tx.insert(chatParticipants).values([{
10085
10103
  chatId,
10086
10104
  agentId: agentAId,
10087
- role: "member"
10105
+ role: "member",
10106
+ mode
10088
10107
  }, {
10089
10108
  chatId,
10090
10109
  agentId: agentBId,
10091
- role: "member"
10110
+ role: "member",
10111
+ mode
10092
10112
  }]);
10093
10113
  if (!chat) throw new Error("Unexpected: INSERT RETURNING produced no row");
10094
10114
  return chat;
@@ -12752,7 +12772,8 @@ async function dispatchTaskSystemMessage(db, task, event, fromStatus) {
12752
12772
  content,
12753
12773
  metadata: {
12754
12774
  taskId: task.id,
12755
- event
12775
+ event,
12776
+ mentions: [task.assigneeAgentId]
12756
12777
  }
12757
12778
  });
12758
12779
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-team-foundation/first-tree-hub",
3
- "version": "0.10.5",
3
+ "version": "0.10.6",
4
4
  "type": "module",
5
5
  "description": "First Tree Hub — unified CLI for server, client, and agent management",
6
6
  "exports": {