@qilin-agent/experimental-agent-team 3.1.3 → 3.1.4

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.
@@ -95,7 +95,7 @@ export const TYPERT = {
95
95
  typeSymbol: '@qilin-agent/experimental-agent-team/client#TeamTaskView',
96
96
  create: _qilin_agent_experimental_agent_team_agentTeams_createTask_result$schema,
97
97
  },
98
- sourceLocation: {"file":"packages/experimental/agent-team/src/index.ts","line":220,"column":9},
98
+ sourceLocation: {"file":"packages/experimental/agent-team/src/index.ts","line":244,"column":9},
99
99
  },
100
100
  {
101
101
  id: '@qilin-agent/experimental-agent-team#agentTeams/updateTask',
@@ -136,7 +136,7 @@ export const TYPERT = {
136
136
  typeSymbol: '@qilin-agent/experimental-agent-team/client#TeamTaskView',
137
137
  create: _qilin_agent_experimental_agent_team_agentTeams_updateTask_result$schema,
138
138
  },
139
- sourceLocation: {"file":"packages/experimental/agent-team/src/index.ts","line":240,"column":9},
139
+ sourceLocation: {"file":"packages/experimental/agent-team/src/index.ts","line":264,"column":9},
140
140
  },
141
141
  ],
142
142
  model: {
@@ -174,8 +174,8 @@ export const TYPERT = {
174
174
  "kind": "method",
175
175
  "name": "sendMessage",
176
176
  "signature": "async sendMessage(caller: Agent, request: SendTeamMessageRequest): Promise<SendTeamMessageResult>",
177
- "summary": "Queue one durable peer message, then attempt immediate delivery.",
178
- "jsDoc": "/**\n * Queue one durable peer message, then attempt immediate delivery.\n * @param caller - exact live sending Team member.\n * @param request - target name, content, and pre-queue cancellation.\n * @returns durable message identity and immediate-delivery observation.\n */"
177
+ "summary": "Steer one peer message into the target inbox or reject the attempt.",
178
+ "jsDoc": "/**\n * Steer one peer message into the target inbox or reject the attempt.\n * @param caller - exact live sending Team member.\n * @param request - target name, content, and cancellation before acceptance.\n * @returns accepted inbox identity; acceptance follows normal Agent persistence and does not await model processing.\n */"
179
179
  },
180
180
  {
181
181
  "kind": "method",
@@ -540,7 +540,7 @@ export const TYPERT = {
540
540
  },
541
541
  {
542
542
  "name": "MessageSourceMap",
543
- "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'system-prompt': SystemPromptMessageSource;\n 'model-selection': { kind: 'model-selection'; } & ContextFormed;\n 'user-approval': { kind: 'user-approval'; } & ContextFormed;\n 'ptc-mode': { kind: 'ptc-mode'; };\n 'tool-registry': { kind: 'tool-registry'; };\n 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; };\n 'sidechat-boundary': { kind: 'sidechat-boundary'; };\n 'agent-message': AgentMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n 'skill-invocation': SkillInvocationSource;\n 'team-message': TeamMessageSource;\n goal: GoalMessageSource;\n 'kylin-host-runner': { kind: 'kylin-host-runner'; };\n schedule: { kind: 'schedule'; } & ContextFormed;\n 'compact-checkpoint': CompactionCheckpointSource;\n 'session-reference': SessionReferenceSource;\n 'user-question-reply': { kind: 'user-question-reply'; callId: ToolCallId; outcome: 'answered'; };\n}"
543
+ "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'system-prompt': SystemPromptMessageSource;\n 'model-selection': { kind: 'model-selection'; } & ContextFormed;\n 'user-approval': { kind: 'user-approval'; } & ContextFormed;\n 'working-directory': { kind: 'working-directory'; };\n 'ptc-mode': { kind: 'ptc-mode'; };\n 'tool-registry': { kind: 'tool-registry'; };\n 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; };\n 'sidechat-boundary': { kind: 'sidechat-boundary'; };\n 'agent-message': AgentMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n 'skill-invocation': SkillInvocationSource;\n 'team-message': TeamMessageSource;\n goal: GoalMessageSource;\n 'kylin-host-runner': { kind: 'kylin-host-runner'; };\n schedule: { kind: 'schedule'; } & ContextFormed;\n 'compact-checkpoint': CompactionCheckpointSource;\n 'session-reference': SessionReferenceSource;\n 'user-question-reply': { kind: 'user-question-reply'; callId: ToolCallId; outcome: 'answered'; };\n}"
544
544
  },
545
545
  {
546
546
  "name": "ModelMessageSource",
@@ -568,7 +568,7 @@ export const TYPERT = {
568
568
  },
569
569
  {
570
570
  "name": "PtcDispatchEventData",
571
- "declaration": "export interface PtcDispatchEventData extends PtcDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n error?: { name: string; code: string; reason?: string; };\n}"
571
+ "declaration": "export interface PtcDispatchEventData extends PtcDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n meta?: JsonValue;\n error?: { name: string; code: string; reason?: string; };\n}"
572
572
  },
573
573
  {
574
574
  "name": "PtcDispatchStartEventData",
@@ -624,7 +624,7 @@ export const TYPERT = {
624
624
  },
625
625
  {
626
626
  "name": "SendTeamMessageResult",
627
- "declaration": "export interface SendTeamMessageResult {\n readonly messageId: TeamMessageId;\n readonly status: 'accepted' | 'queued';\n}"
627
+ "declaration": "export interface SendTeamMessageResult {\n readonly messageId: TeamMessageId;\n}"
628
628
  },
629
629
  {
630
630
  "name": "Session",
@@ -636,7 +636,7 @@ export const TYPERT = {
636
636
  },
637
637
  {
638
638
  "name": "SessionEventMap",
639
- "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'developer/message': { turn: number; step: number; message: DeveloperMessage; headerSeq?: SessionSeq; };\n 'system/message': { turn: number; step: number; message: SystemMessage; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; stream: AssistantStreamRecord[]; usage?: TokenUsage; interrupted?: true; };\n 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[]; };\n 'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; reason?: string; }; meta?: JsonValue; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; startsSeries?: true; };\n 'request/context': RequestContext;\n 'session/end-seed': { inherited?: true; };\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: ToolCallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/ptc-dispatch-start': PtcDispatchStartEventData;\n 'tool/ptc-dispatch': PtcDispatchEventData;\n 'agent-preset/selected': { agentPreset: string; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: import('@qilin-agent/session/types').SessionSeq; };\n 'image/offload': { targets: ImageOffloadTarget[]; };\n 'session/title': SessionTitleEventData;\n 'todo/write': { todos: TodoItem[]; };\n 'model/selection': ModelSelection;\n 'subagent/descriptor': SubagentDescriptorData;\n 'permission/preset': { preset: string; };\n 'subagent/catalog': SubagentCatalogEvent;\n 'feedback/record': FeedbackRecord;\n 'team/member': { version: 2; teamId: TeamId; member: TeamMemberSnapshot; };\n 'team/task': { version: 2; teamId: TeamId; task: TeamTaskSnapshot; };\n 'team/message/queued': { version: 2; teamId: TeamId; message: TeamMessageSnapshot; };\n 'team/message/delivered': { version: 2; teamId: TeamId; messageId: TeamMessageId; targetId: SessionId; };\n 'goal/change': GoalChangeMeta;\n 'feedback/message-put': MessageFeedbackPut;\n 'feedback/message-delete': MessageFeedbackDelete;\n 'schedule/change': ScheduleChange;\n 'compaction/start': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; };\n 'compaction/summary': { compactionId: CompactionId; sourceCommandId?: CommandId; summary: ContentBlock[]; shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; provider: string; model: string; maxTokens?: number; usage?: TokenUsage; } & ({ rawOutput: ContentBlock[]; llmStreamCall: true; } | { rawOutput?: ContentBlock[]; llmStreamCall?: never; });\n 'compaction/end': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; error?: string; };\n 'compaction/prune': { shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; };\n}"
639
+ "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'developer/message': { turn: number; step: number; message: DeveloperMessage; headerSeq?: SessionSeq; };\n 'system/message': { turn: number; step: number; message: SystemMessage; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; stream: AssistantStreamRecord[]; usage?: TokenUsage; interrupted?: true; };\n 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[]; };\n 'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; reason?: string; }; meta?: JsonValue; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; startsSeries?: true; };\n 'request/context': RequestContext;\n 'session/end-seed': { inherited?: true; };\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: ToolCallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'working-directory/change': { cwd: string; };\n 'tool/ptc-dispatch-start': PtcDispatchStartEventData;\n 'tool/ptc-dispatch': PtcDispatchEventData;\n 'agent-preset/selected': { agentPreset: string; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: import('@qilin-agent/session/types').SessionSeq; };\n 'image/offload': { targets: ImageOffloadTarget[]; };\n 'session/title': SessionTitleEventData;\n 'todo/write': { todos: TodoItem[]; };\n 'model/selection': ModelSelection;\n 'permission/preset': { preset: string; };\n 'subagent/descriptor': SubagentDescriptorData;\n 'subagent/catalog': SubagentCatalogEvent;\n 'feedback/record': FeedbackRecord;\n 'team/member': { version: 2; teamId: TeamId; member: TeamMemberSnapshot; };\n 'team/task': { version: 2; teamId: TeamId; task: TeamTaskSnapshot; };\n 'team/message/queued': { version: 2; teamId: TeamId; message: TeamMessageSnapshot; };\n 'team/message/delivered': { version: 2; teamId: TeamId; messageId: TeamMessageId; targetId: SessionId; };\n 'goal/change': GoalChangeMeta;\n 'feedback/message-put': MessageFeedbackPut;\n 'feedback/message-delete': MessageFeedbackDelete;\n 'schedule/change': ScheduleChange;\n 'compaction/start': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; };\n 'compaction/summary': { compactionId: CompactionId; sourceCommandId?: CommandId; summary: ContentBlock[]; shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; provider: string; model: string; maxTokens?: number; usage?: TokenUsage; } & ({ rawOutput: ContentBlock[]; llmStreamCall: true; } | { rawOutput?: ContentBlock[]; llmStreamCall?: never; });\n 'compaction/end': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; error?: string; };\n 'compaction/prune': { shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; };\n}"
640
640
  },
641
641
  {
642
642
  "name": "SessionEventType",
@@ -704,7 +704,7 @@ export const TYPERT = {
704
704
  },
705
705
  {
706
706
  "name": "SubagentCatalogEvent",
707
- "declaration": "export type SubagentCatalogEvent = { readonly childId: SessionId; readonly childCreatedAt: number; } & (({ readonly version: 0; } & KnownCatalogMode) | ({ readonly version: 1; } & (KnownCatalogMode | { readonly mode: 'unknown'; readonly label?: string; })));"
707
+ "declaration": "export type SubagentCatalogEvent = { readonly childId: SessionId; readonly childCreatedAt: number; } & (({ readonly version: 0; } & KnownCatalogMode) | ({ readonly version: 1; } & (KnownCatalogMode | { readonly mode: 'unknown'; readonly label?: string; })) | { readonly version: 2; readonly mode: 'external'; readonly label?: string; });"
708
708
  },
709
709
  {
710
710
  "name": "SubagentDescriptorBase",
@@ -92,7 +92,7 @@ export const TYPERT_REMOTE = {
92
92
  typeSymbol: '@qilin-agent/experimental-agent-team/client#TeamTaskView',
93
93
  create: _qilin_agent_experimental_agent_team_agentTeams_createTask_result$schema,
94
94
  },
95
- sourceLocation: {"file":"packages/experimental/agent-team/src/index.ts","line":220,"column":9},
95
+ sourceLocation: {"file":"packages/experimental/agent-team/src/index.ts","line":244,"column":9},
96
96
  },
97
97
  {
98
98
  id: '@qilin-agent/experimental-agent-team#agentTeams/updateTask',
@@ -133,7 +133,7 @@ export const TYPERT_REMOTE = {
133
133
  typeSymbol: '@qilin-agent/experimental-agent-team/client#TeamTaskView',
134
134
  create: _qilin_agent_experimental_agent_team_agentTeams_updateTask_result$schema,
135
135
  },
136
- sourceLocation: {"file":"packages/experimental/agent-team/src/index.ts","line":240,"column":9},
136
+ sourceLocation: {"file":"packages/experimental/agent-team/src/index.ts","line":264,"column":9},
137
137
  },
138
138
  ],
139
139
  }
@@ -1,4 +1,4 @@
1
- /** Agent Teams service façade over roster, mailbox, task, and runtime lifecycle owners. */
1
+ /** Agent Teams service façade over roster, messaging, task, and runtime lifecycle owners. */
2
2
  import { Context } from '@qilin-agent/kylin';
3
3
  import z from '@qilin-agent/schemastery';
4
4
  import type { Agent } from '@qilin-agent/agent';
@@ -30,7 +30,6 @@ export declare class TeamService extends TypertRemoteService {
30
30
  private readonly lifecycle;
31
31
  private readonly journal;
32
32
  private readonly roster;
33
- private readonly mailbox;
34
33
  private readonly tasks;
35
34
  constructor(ctx: Context, config?: Config);
36
35
  /**
@@ -53,12 +52,19 @@ export declare class TeamService extends TypertRemoteService {
53
52
  */
54
53
  spawnTeammate(caller: Agent, request: SpawnTeammateRequest): Promise<SpawnTeammateResult>;
55
54
  /**
56
- * Queue one durable peer message, then attempt immediate delivery.
55
+ * Steer one peer message into the target inbox or reject the attempt.
57
56
  * @param caller - exact live sending Team member.
58
- * @param request - target name, content, and pre-queue cancellation.
59
- * @returns durable message identity and immediate-delivery observation.
57
+ * @param request - target name, content, and cancellation before acceptance.
58
+ * @returns accepted inbox identity; acceptance follows normal Agent persistence and does not await model processing.
60
59
  */
61
60
  sendMessage(caller: Agent, request: SendTeamMessageRequest): Promise<SendTeamMessageResult>;
61
+ /**
62
+ * Admit one peer message and steer it into the target's inbox.
63
+ * @param caller - exact live sending Team member.
64
+ * @param request - target name, content, and signal already joined with runtime cancellation.
65
+ * @returns the durable message identity carried by the delivered source.
66
+ */
67
+ private sendAdmitted;
62
68
  /**
63
69
  * Create one unowned pending task in the Team Lead log.
64
70
  * @param caller - exact live Team member creating the task.
@@ -133,7 +139,7 @@ export declare class TeamService extends TypertRemoteService {
133
139
  tryMembership(agent: Agent): TeamMembership | undefined;
134
140
  /** Queue one contained recovery pass after publication has unwound. */
135
141
  private scheduleRecovery;
136
- /** Reconcile roster provisioning before retrying that member's pending mailbox. */
142
+ /** Reconcile roster provisioning when one Team member Session starts. */
137
143
  private recoverFor;
138
144
  /** Stop Team-owned live branches and release every waiter before service disposal completes. */
139
145
  private disposeRuntime;
@@ -1,4 +1,4 @@
1
- /** Agent Teams service façade over roster, mailbox, task, and runtime lifecycle owners. */
1
+ /** Agent Teams service façade over roster, messaging, task, and runtime lifecycle owners. */
2
2
  var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
3
  var useValue = arguments.length > 2;
4
4
  for (var i = 0; i < initializers.length; i++) {
@@ -33,23 +33,24 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
33
33
  if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
34
  done = true;
35
35
  };
36
+ import { randomUUID } from 'node:crypto';
36
37
  import z from '@qilin-agent/schemastery';
38
+ import { createUserMessage } from '@qilin-agent/llm';
39
+ import { steerHostSubagentPrompt } from '@qilin-agent/subagent/internal';
37
40
  import { Remote, TypertRemoteService } from '@qilin-agent/typert-protocol';
38
41
  import { TeamActivity } from "./activity.js";
39
42
  import { errorMessage, TeamError } from "./error.js";
40
43
  import { TeamJournal } from "./journal.js";
41
44
  import { TeamRuntimeLifecycle } from "./lifecycle.js";
42
- import { TeamMailbox } from "./mailbox.js";
43
45
  import { teamProjectionDefinition } from "./projection.js";
44
46
  import { teamWireError } from "./remote.js";
45
- import { TeamRoster } from "./roster.js";
47
+ import { resolveActiveMember, TeamRoster } from "./roster.js";
46
48
  import { TeamTaskBoard } from "./task-board.js";
47
- import { TeamId } from "./types.js";
49
+ import { TeamId, TeamMessageId } from "./types.js";
48
50
  export { TeamId, TeamMessageId, TeamTaskId } from "./types.js";
49
51
  export { TeamError } from "./error.js";
50
52
  const DEFAULT_MAX_MEMBERS = 16;
51
53
  const DEFAULT_MAX_TASKS = 256;
52
- const DEFAULT_MAX_PENDING_MESSAGES = 64;
53
54
  const DEFAULT_MAX_MESSAGE_BYTES = 65_536;
54
55
  const DEFAULT_DISPOSAL_TIMEOUT_MS = 5_000;
55
56
  /** Validate one positive safe-integer deployment limit. */
@@ -83,7 +84,6 @@ let TeamService = (() => {
83
84
  static Config = z.object({
84
85
  maxMembers: z.number().step(1).min(1).default(DEFAULT_MAX_MEMBERS),
85
86
  maxTasks: z.number().step(1).min(1).default(DEFAULT_MAX_TASKS),
86
- maxPendingMessagesPerMember: z.number().step(1).min(1).default(DEFAULT_MAX_PENDING_MESSAGES),
87
87
  maxMessageBytes: z.number().step(1).min(1).default(DEFAULT_MAX_MESSAGE_BYTES),
88
88
  disposalTimeoutMs: z.number().step(1).min(1).default(DEFAULT_DISPOSAL_TIMEOUT_MS),
89
89
  });
@@ -93,14 +93,12 @@ let TeamService = (() => {
93
93
  lifecycle;
94
94
  journal;
95
95
  roster;
96
- mailbox;
97
96
  tasks;
98
97
  constructor(ctx, config = {}) {
99
98
  super(ctx, 'agentTeams');
100
99
  this.config = {
101
100
  maxMembers: positiveLimit('maxMembers', config.maxMembers ?? DEFAULT_MAX_MEMBERS),
102
101
  maxTasks: positiveLimit('maxTasks', config.maxTasks ?? DEFAULT_MAX_TASKS),
103
- maxPendingMessagesPerMember: positiveLimit('maxPendingMessagesPerMember', config.maxPendingMessagesPerMember ?? DEFAULT_MAX_PENDING_MESSAGES),
104
102
  maxMessageBytes: positiveLimit('maxMessageBytes', config.maxMessageBytes ?? DEFAULT_MAX_MESSAGE_BYTES),
105
103
  disposalTimeoutMs: positiveLimit('disposalTimeoutMs', config.disposalTimeoutMs ?? DEFAULT_DISPOSAL_TIMEOUT_MS),
106
104
  };
@@ -108,9 +106,7 @@ let TeamService = (() => {
108
106
  this.lifecycle = new TeamRuntimeLifecycle(this.config.disposalTimeoutMs);
109
107
  this.journal = new TeamJournal(ctx, (root) => { this.activity.notify(TeamId(root.id)); });
110
108
  this.roster = new TeamRoster(ctx, this.journal, this.lifecycle, this.config.maxMembers);
111
- this.mailbox = new TeamMailbox(ctx, this.journal, this.roster, this.lifecycle, this.config.maxPendingMessagesPerMember, this.config.maxMessageBytes);
112
109
  this.tasks = new TeamTaskBoard(this.journal, this.config.maxTasks);
113
- ctx.on('session/event', (session, event) => { this.mailbox.observeSessionEvent(session, event); });
114
110
  ctx.on('agent/created', ({ agent }) => { this.scheduleRecovery(agent); });
115
111
  ctx.on('agent/status', ({ agent }) => {
116
112
  const membership = this.roster.tryMembership(agent);
@@ -157,13 +153,53 @@ let TeamService = (() => {
157
153
  return await this.roster.spawn(caller, request);
158
154
  }
159
155
  /**
160
- * Queue one durable peer message, then attempt immediate delivery.
156
+ * Steer one peer message into the target inbox or reject the attempt.
161
157
  * @param caller - exact live sending Team member.
162
- * @param request - target name, content, and pre-queue cancellation.
163
- * @returns durable message identity and immediate-delivery observation.
158
+ * @param request - target name, content, and cancellation before acceptance.
159
+ * @returns accepted inbox identity; acceptance follows normal Agent persistence and does not await model processing.
164
160
  */
165
161
  async sendMessage(caller, request) {
166
- return await this.mailbox.send(caller, request);
162
+ if (this.lifecycle.disposed)
163
+ throw new TeamError('Agent Teams service is disposing', 'TEAM_DISPOSED');
164
+ return await this.lifecycle.track(this.sendAdmitted(caller, {
165
+ ...request,
166
+ signal: AbortSignal.any([request.signal, this.lifecycle.signal]),
167
+ }));
168
+ }
169
+ /**
170
+ * Admit one peer message and steer it into the target's inbox.
171
+ * @param caller - exact live sending Team member.
172
+ * @param request - target name, content, and signal already joined with runtime cancellation.
173
+ * @returns the durable message identity carried by the delivered source.
174
+ */
175
+ async sendAdmitted(caller, request) {
176
+ const membership = this.roster.membership(caller);
177
+ request.signal.throwIfAborted();
178
+ const { root } = membership;
179
+ const target = resolveActiveMember(root, this.journal.state(root), request.target);
180
+ if (target.id === caller.id)
181
+ throw new TeamError('a Team member cannot message itself', 'TEAM_SELF_MESSAGE');
182
+ const messageId = TeamMessageId(`team-message-${randomUUID()}`);
183
+ const source = {
184
+ kind: 'team-message',
185
+ teamId: TeamId(root.id),
186
+ messageId,
187
+ senderId: caller.id,
188
+ senderName: membership.name,
189
+ };
190
+ const content = [
191
+ { type: 'text', text: `Team message ${messageId} from ${membership.name}:` },
192
+ ...structuredClone(request.content),
193
+ ];
194
+ if (Buffer.byteLength(JSON.stringify(content), 'utf8') > this.config.maxMessageBytes) {
195
+ throw new TeamError(`team message exceeds ${this.config.maxMessageBytes} bytes`, 'TEAM_MESSAGE_TOO_LARGE');
196
+ }
197
+ if (target.id === root.id)
198
+ root.steer(createUserMessage({ content, source }));
199
+ else
200
+ await steerHostSubagentPrompt(this.ctx.subagents, root, target.id, content, source, request.signal);
201
+ this.activity.notify(membership.id);
202
+ return { messageId };
167
203
  }
168
204
  /**
169
205
  * Create one unowned pending task in the Team Lead log.
@@ -276,18 +312,16 @@ let TeamService = (() => {
276
312
  });
277
313
  });
278
314
  }
279
- /** Reconcile roster provisioning before retrying that member's pending mailbox. */
315
+ /** Reconcile roster provisioning when one Team member Session starts. */
280
316
  async recoverFor(agent) {
281
317
  await this.roster.recoverFor(agent, this.lifecycle.signal);
282
- await this.mailbox.recoverFor(agent, this.lifecycle.signal);
283
318
  }
284
319
  /** Stop Team-owned live branches and release every waiter before service disposal completes. */
285
320
  async disposeRuntime() {
286
321
  this.lifecycle.close();
287
322
  this.activity.close();
288
323
  const failures = [];
289
- await this.lifecycle.settle(this.roster.pendingCreations(), failures);
290
- await this.lifecycle.settle(this.mailbox.pendingDispatches(), failures);
324
+ await this.lifecycle.settle(this.lifecycle.pending(), failures);
291
325
  for (const [root, childIds] of this.roster.liveChildrenByRoot()) {
292
326
  try {
293
327
  await this.roster.stopTeammates(root, childIds);
@@ -2,6 +2,7 @@
2
2
  /** Owns the single Team runtime cancellation fact and disposal timeout. */
3
3
  export declare class TeamRuntimeLifecycle {
4
4
  private readonly disposalTimeoutMs;
5
+ private readonly operations;
5
6
  private readonly controller;
6
7
  /**
7
8
  * @param disposalTimeoutMs - maximum wait for one disposal settlement operation.
@@ -17,6 +18,17 @@ export declare class TeamRuntimeLifecycle {
17
18
  private isCancellation;
18
19
  /** Close Team runtime admission and cancel admitted interruptible work. */
19
20
  close(): void;
21
+ /**
22
+ * Track an admitted send or complete creation transaction until it settles.
23
+ * @param operation - asynchronous work owned by this runtime.
24
+ * @returns the same operation.
25
+ */
26
+ track<T>(operation: Promise<T>): Promise<T>;
27
+ /**
28
+ * Capture outstanding operations after closing admission.
29
+ * @returns admitted work still awaiting settlement.
30
+ */
31
+ pending(): readonly Promise<unknown>[];
20
32
  /**
21
33
  * Await admitted operations and retain failures other than runtime cancellation.
22
34
  * @param operations - admitted operations captured after the admission cutoff.
@@ -3,6 +3,7 @@ import { TeamError } from "./error.js";
3
3
  /** Owns the single Team runtime cancellation fact and disposal timeout. */
4
4
  export class TeamRuntimeLifecycle {
5
5
  disposalTimeoutMs;
6
+ operations = new Set();
6
7
  controller = new AbortController();
7
8
  /**
8
9
  * @param disposalTimeoutMs - maximum wait for one disposal settlement operation.
@@ -43,6 +44,23 @@ export class TeamRuntimeLifecycle {
43
44
  close() {
44
45
  this.controller.abort(new TeamError('Agent Teams service disposed', 'TEAM_DISPOSED'));
45
46
  }
47
+ /**
48
+ * Track an admitted send or complete creation transaction until it settles.
49
+ * @param operation - asynchronous work owned by this runtime.
50
+ * @returns the same operation.
51
+ */
52
+ track(operation) {
53
+ this.operations.add(operation);
54
+ void operation.then(() => { this.operations.delete(operation); }, () => { this.operations.delete(operation); });
55
+ return operation;
56
+ }
57
+ /**
58
+ * Capture outstanding operations after closing admission.
59
+ * @returns admitted work still awaiting settlement.
60
+ */
61
+ pending() {
62
+ return [...this.operations];
63
+ }
46
64
  /**
47
65
  * Await admitted operations and retain failures other than runtime cancellation.
48
66
  * @param operations - admitted operations captured after the admission cutoff.
@@ -31,7 +31,6 @@ export declare class TeamRoster {
31
31
  private readonly journal;
32
32
  private readonly lifecycle;
33
33
  private readonly maxMembers;
34
- private readonly inFlightCreations;
35
34
  /**
36
35
  * @param ctx - Team service context with Agent, Session, persistence, and subagent services.
37
36
  * @param journal - authoritative Lead-log transaction owner.
@@ -64,11 +63,6 @@ export declare class TeamRoster {
64
63
  * @returns the active roster row.
65
64
  */
66
65
  spawn(caller: Agent, request: SpawnTeammateRequest): Promise<SpawnTeammateResult>;
67
- /**
68
- * Return admitted creation operations captured for ordered disposal.
69
- * @returns detached snapshot ordered only by Set insertion.
70
- */
71
- pendingCreations(): readonly Promise<unknown>[];
72
66
  /**
73
67
  * Reconcile provisioning state when one Team member Session starts.
74
68
  * @param agent - newly started exact live Agent.
@@ -31,7 +31,6 @@ export class TeamRoster {
31
31
  journal;
32
32
  lifecycle;
33
33
  maxMembers;
34
- inFlightCreations = new Set();
35
34
  /**
36
35
  * @param ctx - Team service context with Agent, Session, persistence, and subagent services.
37
36
  * @param journal - authoritative Lead-log transaction owner.
@@ -142,21 +141,7 @@ export class TeamRoster {
142
141
  async spawn(caller, request) {
143
142
  if (this.lifecycle.disposed)
144
143
  throw new TeamError('Agent Teams service is disposing', 'TEAM_DISPOSED');
145
- const operation = this.spawnAdmitted(caller, request);
146
- this.inFlightCreations.add(operation);
147
- try {
148
- return await operation;
149
- }
150
- finally {
151
- this.inFlightCreations.delete(operation);
152
- }
153
- }
154
- /**
155
- * Return admitted creation operations captured for ordered disposal.
156
- * @returns detached snapshot ordered only by Set insertion.
157
- */
158
- pendingCreations() {
159
- return [...this.inFlightCreations];
144
+ return await this.lifecycle.track(this.spawnAdmitted(caller, request));
160
145
  }
161
146
  /**
162
147
  * Reconcile provisioning state when one Team member Session starts.
@@ -216,7 +201,7 @@ export class TeamRoster {
216
201
  * @param childIds - selected roster child ids.
217
202
  */
218
203
  async stopTeammates(root, childIds) {
219
- await this.lifecycle.withTimeout(this.ctx.subagents.drainContinuableChildren(root, childIds));
204
+ await this.lifecycle.withTimeout(this.ctx.subagents.drainChildren(root, childIds));
220
205
  }
221
206
  /** Perform one creation admitted before the Team runtime disposal cutoff. */
222
207
  async spawnAdmitted(caller, request) {
@@ -250,7 +235,7 @@ export class TeamRoster {
250
235
  });
251
236
  let started;
252
237
  try {
253
- started = await this.ctx.subagents.startContinuable({
238
+ started = await this.ctx.subagents.startActivation({
254
239
  childId,
255
240
  provider: request.provider,
256
241
  label: description,
@@ -259,7 +244,11 @@ export class TeamRoster {
259
244
  parent: root,
260
245
  },
261
246
  signal,
247
+ delivery: 'parent',
262
248
  });
249
+ if (started.messageId === undefined) {
250
+ throw new TeamError('the spawned teammate accepted no initial prompt', 'TEAM_PROMPT_NOT_ACCEPTED');
251
+ }
263
252
  await this.checkpointInitialPrompt(childId, started.messageId, signal);
264
253
  }
265
254
  catch (error) {
@@ -128,8 +128,6 @@ export interface Config {
128
128
  readonly maxMembers?: number;
129
129
  /** Maximum non-deleted tasks retained by one Team. */
130
130
  readonly maxTasks?: number;
131
- /** Maximum queued-minus-delivered messages for one target member. */
132
- readonly maxPendingMessagesPerMember?: number;
133
131
  /** Maximum UTF-8 bytes in one complete sender-framed delivery. */
134
132
  readonly maxMessageBytes?: number;
135
133
  /** Maximum milliseconds allowed for Team-owned runtime disposal. */
@@ -154,10 +152,9 @@ export interface SendTeamMessageRequest {
154
152
  readonly content: ContentBlock[];
155
153
  readonly signal: AbortSignal;
156
154
  }
157
- /** Result after a peer message enters the durable mailbox. */
155
+ /** Result after a peer message enters the target inbox. */
158
156
  export interface SendTeamMessageResult {
159
157
  readonly messageId: TeamMessageId;
160
- readonly status: 'accepted' | 'queued';
161
158
  }
162
159
  /** Input for creating one shared task. */
163
160
  export interface CreateTeamTaskRequest {
@@ -197,13 +194,13 @@ declare module '@qilin-agent/session/types' {
197
194
  teamId: TeamId;
198
195
  task: TeamTaskSnapshot;
199
196
  };
200
- /** Durable mailbox enqueue, stored before delivery is attempted. */
197
+ /** Historical mailbox enqueue; new sends use the target Agent inbox. */
201
198
  'team/message/queued': {
202
199
  version: 2;
203
200
  teamId: TeamId;
204
201
  message: TeamMessageSnapshot;
205
202
  };
206
- /** Durable acknowledgement that the target Session recorded the message. */
203
+ /** Historical acknowledgement that the target Session recorded a queued message. */
207
204
  'team/message/delivered': {
208
205
  version: 2;
209
206
  teamId: TeamId;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qilin-agent/experimental-agent-team",
3
3
  "description": "Implicit-root Agent Teams roster, durable peer mailbox, and shared task DAG",
4
- "version": "3.1.3",
4
+ "version": "3.1.4",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -54,33 +54,33 @@
54
54
  "license": "MIT",
55
55
  "dependencies": {
56
56
  "zod": "^4.4.3",
57
- "@qilin-agent/brand": "3.1.3",
58
- "@qilin-agent/schemastery": "~3.18.3"
57
+ "@qilin-agent/schemastery": "~3.18.3",
58
+ "@qilin-agent/brand": "3.1.4"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@qilin-agent/kylin": "~4.0.3",
62
- "@qilin-agent/agent": "3.1.3",
63
- "@qilin-agent/session-projection": "3.1.3",
64
- "@qilin-agent/subagent": "3.1.3",
65
- "@qilin-agent/session-persistence": "3.1.3",
66
- "@qilin-agent/session": "3.1.3",
67
- "@qilin-agent/typert-protocol": "3.1.3",
68
- "@qilin-agent/llm": "3.1.3"
62
+ "@qilin-agent/agent": "3.1.4",
63
+ "@qilin-agent/session": "3.1.4",
64
+ "@qilin-agent/session-persistence": "3.1.4",
65
+ "@qilin-agent/llm": "3.1.4",
66
+ "@qilin-agent/session-projection": "3.1.4",
67
+ "@qilin-agent/subagent": "3.1.4",
68
+ "@qilin-agent/typert-protocol": "3.1.4"
69
69
  },
70
70
  "devDependencies": {
71
+ "@qilin-agent/agent-loop": "3.1.4",
72
+ "@qilin-agent/agent": "3.1.4",
73
+ "@qilin-agent/agent-loop-testkit": "3.1.4",
71
74
  "@qilin-agent/kylin": "~4.0.3",
72
- "@qilin-agent/agent-loop": "3.1.3",
73
- "@qilin-agent/agent-loop-testkit": "3.1.3",
74
- "@qilin-agent/agent": "3.1.3",
75
- "@qilin-agent/llm": "3.1.3",
76
- "@qilin-agent/session": "3.1.3",
77
- "@qilin-agent/session-persistence": "3.1.3",
78
- "@qilin-agent/session-persistence-jsonl": "3.1.3",
79
- "@qilin-agent/session-projection": "3.1.3",
80
- "@qilin-agent/session-query": "3.1.3",
81
- "@qilin-agent/subagent-fork-in-process": "3.1.3",
82
- "@qilin-agent/subagent": "3.1.3",
83
- "@qilin-agent/subagent-spawn-in-process": "3.1.3",
84
- "@qilin-agent/typert-protocol": "3.1.3"
75
+ "@qilin-agent/llm": "3.1.4",
76
+ "@qilin-agent/session": "3.1.4",
77
+ "@qilin-agent/session-persistence": "3.1.4",
78
+ "@qilin-agent/session-persistence-jsonl": "3.1.4",
79
+ "@qilin-agent/session-projection": "3.1.4",
80
+ "@qilin-agent/subagent": "3.1.4",
81
+ "@qilin-agent/session-query": "3.1.4",
82
+ "@qilin-agent/subagent-fork-in-process": "3.1.4",
83
+ "@qilin-agent/typert-protocol": "3.1.4",
84
+ "@qilin-agent/subagent-spawn-in-process": "3.1.4"
85
85
  }
86
86
  }
@@ -1,78 +0,0 @@
1
- /** Durable Team mailbox admission, target-local dispatch, acknowledgement, and recovery. */
2
- import type { Context } from '@qilin-agent/kylin';
3
- import type { Agent } from '@qilin-agent/agent';
4
- import type { Session, SessionEvent } from '@qilin-agent/session';
5
- import type { TeamJournal } from './journal.ts';
6
- import type { TeamRuntimeLifecycle } from './lifecycle.ts';
7
- import type { TeamRoster } from './roster.ts';
8
- import type { SendTeamMessageRequest, SendTeamMessageResult } from './types.ts';
9
- /** Owns every process-local state transition for the durable Team mailbox. */
10
- export declare class TeamMailbox {
11
- private readonly ctx;
12
- private readonly journal;
13
- private readonly roster;
14
- private readonly lifecycle;
15
- private readonly maxPendingMessagesPerMember;
16
- private readonly maxMessageBytes;
17
- private readonly dispatchTails;
18
- private readonly inFlightMessages;
19
- private readonly inFlightDispatches;
20
- /**
21
- * @param ctx - Team service context with Agent, Session, persistence, and subagent services.
22
- * @param journal - authoritative Lead-log transaction owner.
23
- * @param roster - Team membership and member-name resolver.
24
- * @param lifecycle - shared Team runtime admission cutoff.
25
- * @param maxPendingMessagesPerMember - per-target queued-minus-delivered limit.
26
- * @param maxMessageBytes - maximum complete sender-framed delivery size.
27
- */
28
- constructor(ctx: Context, journal: TeamJournal, roster: TeamRoster, lifecycle: TeamRuntimeLifecycle, maxPendingMessagesPerMember: number, maxMessageBytes: number);
29
- /**
30
- * Queue one durable peer message, then attempt immediate delivery.
31
- * @param caller - exact live sending Team member.
32
- * @param request - target name, content, and pre-queue cancellation.
33
- * @returns durable message identity and immediate-delivery observation.
34
- */
35
- send(caller: Agent, request: SendTeamMessageRequest): Promise<SendTeamMessageResult>;
36
- /**
37
- * Observe target-side durable receipts and checkpoint their Lead-log acknowledgement.
38
- * @param session - exact target Session receiving the event.
39
- * @param event - newly appended Session event.
40
- */
41
- observeSessionEvent(session: Session, event: SessionEvent): void;
42
- /**
43
- * Retry durable pending messages relevant to one started Team member.
44
- * @param agent - newly started exact live Agent.
45
- * @param signal - shared runtime cancellation.
46
- */
47
- recoverFor(agent: Agent, signal: AbortSignal): Promise<void>;
48
- /**
49
- * Return admitted dispatch and acknowledgement operations captured for disposal.
50
- * @returns detached snapshot ordered only by Set insertion.
51
- */
52
- pendingDispatches(): readonly Promise<unknown>[];
53
- /** Queue and dispatch one mailbox item admitted before the disposal cutoff. */
54
- private sendAdmitted;
55
- /** Attempt one queued message exactly once in this process at a time. */
56
- private tryDispatch;
57
- /** Track one dispatch transaction through delivery admission or contained failure. */
58
- private trackDispatch;
59
- /** Attempt one queued message admitted before the service lifecycle cutoff. */
60
- private tryDispatchAdmitted;
61
- /** Serialize delivery admission for one durable target in queued order. */
62
- private serializeDispatch;
63
- /** Deliver every pending target message through `message` in durable queue order. */
64
- private dispatchThrough;
65
- /** Attempt one queued delivery after target-local ordering admits it. */
66
- private dispatchOnce;
67
- /** Flush one live target receipt before the Lead records its delivered edge. */
68
- private checkpointDelivered;
69
- /** Record delivery unless the acknowledgement already exists. */
70
- private markDelivered;
71
- /** Whether a target Session already contains the durable message identity. */
72
- private targetRecorded;
73
- /** Frame peer content with stable sender and message identity for the receiving model. */
74
- private deliveryContent;
75
- /** Read an inactive target's durable log before cold resume; uncertainty keeps the mailbox queued. */
76
- private persistedTargetRecorded;
77
- }
78
- //# sourceMappingURL=mailbox.d.ts.map