@ai-agent-forge/plugin-subagent-delegate 0.88.13 → 0.88.15

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.d.ts CHANGED
@@ -21,6 +21,8 @@ export type { SubagentRunnerPoolOptionsV1, SubagentRunnerPoolStatsV1, SubagentRu
21
21
  export { createPooledAgentTaskAdapterV1, SubagentRunnerPoolError, validateSubagentRunnerPoolOptionsV1, } from "./runner-pool.ts";
22
22
  export type { NodeSubagentRunnerSpawnerOptionsV1 } from "./runner-spawn.ts";
23
23
  export { createNodeSubagentRunnerSpawnerV1 } from "./runner-spawn.ts";
24
+ export type { AgentTaskSchedulerProviderOptionsV1 } from "./scheduler-capability.ts";
25
+ export { createAgentTaskSchedulerCapabilityProviderV1, projectSchedulerResultV1, projectSchedulerStatusV1, } from "./scheduler-capability.ts";
24
26
  export type { SelfInvocationV1 } from "./self-invocation.ts";
25
27
  export { resolveSelfInvocationV1 } from "./self-invocation.ts";
26
28
  export { createAgentTaskApiAdapterV1 } from "./shared-adapter.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,YAAY,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACrG,YAAY,EACX,sBAAsB,EACtB,kCAAkC,EAClC,gCAAgC,EAChC,iCAAiC,EACjC,+BAA+B,EAC/B,sCAAsC,EACtC,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,EACxB,sBAAsB,EACtB,gCAAgC,EAChC,4BAA4B,EAC5B,0BAA0B,EAC1B,+BAA+B,EAC/B,4BAA4B,EAC5B,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,kBAAkB,EAClB,gBAAgB,IAAI,gCAAgC,EACpD,kBAAkB,EAClB,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,GACnB,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,qBAAqB,EACrB,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,iBAAiB,EACjB,WAAW,GACX,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,cAAc,EACd,uBAAuB,EACvB,aAAa,GACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACnE,YAAY,EACX,2BAA2B,EAC3B,yBAAyB,EACzB,oBAAoB,EACpB,2BAA2B,GAC3B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACN,8BAA8B,EAC9B,uBAAuB,EACvB,mCAAmC,GACnC,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,kCAAkC,EAAE,MAAM,mBAAmB,CAAC;AAE5E,OAAO,EAAE,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AACtE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,YAAY,EACX,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,8BAA8B,EAC9B,iBAAiB,EACjB,oBAAoB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,2BAA2B,GAC3B,MAAM,uBAAuB,CAAC","sourcesContent":["/**\n * Subagent delegate capability plugin: the first production orchestrator over\n * the plugin-level `SubagentRuntime` (D-044), extracted from the host's\n * `src/capabilities/subagent-delegate.ts` (D-075 S4, third batch).\n *\n * Library face (`createSubagentDelegateCapability(api, options?)`) keeps the\n * explicit-options signature for in-package tests and third-party embedders;\n * the plugin entry (`./entry.ts`, manifest-loaded) assembles the same options\n * from the host services (`api.host`) and the agent-dir config channel. The\n * scheduler, runner pool, remote/shared adapters, multi-agent task registry\n * and self-invocation probe migrate with the capability and are re-exported\n * here so consumers keep one import face.\n */\n\n// 通信接线与信箱消息形状是 plugin-sdk 公共契约(D-075 S4 第三批迁入 SDK),此处再导出。\nexport type { SubagentCommunicationWiringV1, SubagentInboxMessageV1 } from \"@agent-forge/plugin-sdk\";\nexport type {\n\tSubagentCancelResultV1,\n\tSubagentDelegateBackgroundResultV1,\n\tSubagentDelegateBackgroundTaskV1,\n\tSubagentDelegateCapabilityOptions,\n\tSubagentDelegateContextAnchorV1,\n\tSubagentDelegateContextFailedAttemptV1,\n\tSubagentDelegateContextV1,\n\tSubagentDelegateErrorCodesV1,\n\tSubagentDelegateResultV1,\n\tSubagentDelegateRoleV1,\n\tSubagentDelegateTaskProjectionV1,\n\tSubagentDelegateTaskStatusV1,\n\tSubagentResultReadResultV1,\n\tSubagentRoleCatalogResolutionV1,\n\tSubagentRoleDefinitionViewV1,\n\tSubagentRoleListEntryV1,\n\tSubagentRoleListResultV1,\n\tSubagentRoleRemoveResultV1,\n\tSubagentRoleSetResultV1,\n\tSubagentRoleViewResultV1,\n\tSubagentSessionListEntryV1,\n\tSubagentSessionListResultV1,\n\tSubagentSessionRoleMergeV1,\n\tSubagentSessionRoleRecordV1,\n\tSubagentSessionRolesStateV1,\n} from \"./delegate.ts\";\nexport {\n\tcapabilityManifest,\n\tcreateCapability as createSubagentDelegateCapability,\n\tmergeSubagentRoles,\n\treadSessionRoles,\n\tresolveSubagentRoleCatalog,\n\tSESSION_ROLE_STATE_ENTRY,\n\tSubagentDelegateError,\n\tseedFactoryRoleCatalog,\n\tsubagentRoleCatalogPath,\n\ttoSessionRoleRecord,\n} from \"./delegate.ts\";\nexport type {\n\tAgentTaskErrorCodesV1,\n\tAgentTaskEventV1,\n\tAgentTaskRegistryOptionsV1,\n\tAgentTaskRegistryV1,\n\tAgentTaskStatusV1,\n\tAgentTaskV1,\n} from \"./multi-agent-tasks.ts\";\nexport {\n\tAgentTaskError,\n\tcreateAgentTaskRegistry,\n\treplayTaskLog,\n} from \"./multi-agent-tasks.ts\";\nexport { createRemoteAgentTaskAdapter } from \"./remote-adapter.ts\";\nexport type {\n\tSubagentRunnerPoolOptionsV1,\n\tSubagentRunnerPoolStatsV1,\n\tSubagentRunnerPoolV1,\n\tSubagentRunnerSpawnHandleV1,\n} from \"./runner-pool.ts\";\n\nexport {\n\tcreatePooledAgentTaskAdapterV1,\n\tSubagentRunnerPoolError,\n\tvalidateSubagentRunnerPoolOptionsV1,\n} from \"./runner-pool.ts\";\nexport type { NodeSubagentRunnerSpawnerOptionsV1 } from \"./runner-spawn.ts\";\n\nexport { createNodeSubagentRunnerSpawnerV1 } from \"./runner-spawn.ts\";\nexport type { SelfInvocationV1 } from \"./self-invocation.ts\";\nexport { resolveSelfInvocationV1 } from \"./self-invocation.ts\";\nexport { createAgentTaskApiAdapterV1 } from \"./shared-adapter.ts\";\nexport type {\n\tSchedulerTaskRecordV1,\n\tSubagentAdmissionGateV1,\n\tSubagentCancelByIdResultV1,\n\tSubagentRuntimeErrorCodesV1,\n\tSubagentRuntimeLimitsV1,\n\tSubagentRuntimeOptionsV1,\n\tSubagentRuntimeStatus,\n\tSubagentRuntimeSubmitRequestV1,\n\tSubagentRuntimeV1,\n\tSubagentTaskHandleV1,\n} from \"./subagent-runtime.ts\";\nexport {\n\tcreateSubagentRuntime,\n\tSubagentRuntimeError,\n\ttoAgentTaskStatusProjection,\n} from \"./subagent-runtime.ts\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,YAAY,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACrG,YAAY,EACX,sBAAsB,EACtB,kCAAkC,EAClC,gCAAgC,EAChC,iCAAiC,EACjC,+BAA+B,EAC/B,sCAAsC,EACtC,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,EACxB,sBAAsB,EACtB,gCAAgC,EAChC,4BAA4B,EAC5B,0BAA0B,EAC1B,+BAA+B,EAC/B,4BAA4B,EAC5B,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,GAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,kBAAkB,EAClB,gBAAgB,IAAI,gCAAgC,EACpD,kBAAkB,EAClB,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,GACnB,MAAM,eAAe,CAAC;AACvB,YAAY,EACX,qBAAqB,EACrB,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,iBAAiB,EACjB,WAAW,GACX,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,cAAc,EACd,uBAAuB,EACvB,aAAa,GACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACnE,YAAY,EACX,2BAA2B,EAC3B,yBAAyB,EACzB,oBAAoB,EACpB,2BAA2B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACN,8BAA8B,EAC9B,uBAAuB,EACvB,mCAAmC,GACnC,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,kCAAkC,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AACtE,YAAY,EAAE,mCAAmC,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EACN,4CAA4C,EAC5C,wBAAwB,EACxB,wBAAwB,GACxB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,YAAY,EACX,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,8BAA8B,EAC9B,iBAAiB,EACjB,oBAAoB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,2BAA2B,GAC3B,MAAM,uBAAuB,CAAC","sourcesContent":["/**\n * Subagent delegate capability plugin: the first production orchestrator over\n * the plugin-level `SubagentRuntime` (D-044), extracted from the host's\n * `src/capabilities/subagent-delegate.ts` (D-075 S4, third batch).\n *\n * Library face (`createSubagentDelegateCapability(api, options?)`) keeps the\n * explicit-options signature for in-package tests and third-party embedders;\n * the plugin entry (`./entry.ts`, manifest-loaded) assembles the same options\n * from the host services (`api.host`) and the agent-dir config channel. The\n * scheduler, runner pool, remote/shared adapters, multi-agent task registry\n * and self-invocation probe migrate with the capability and are re-exported\n * here so consumers keep one import face.\n */\n\n// 通信接线与信箱消息形状是 plugin-sdk 公共契约(D-075 S4 第三批迁入 SDK),此处再导出。\nexport type { SubagentCommunicationWiringV1, SubagentInboxMessageV1 } from \"@agent-forge/plugin-sdk\";\nexport type {\n\tSubagentCancelResultV1,\n\tSubagentDelegateBackgroundResultV1,\n\tSubagentDelegateBackgroundTaskV1,\n\tSubagentDelegateCapabilityOptions,\n\tSubagentDelegateContextAnchorV1,\n\tSubagentDelegateContextFailedAttemptV1,\n\tSubagentDelegateContextV1,\n\tSubagentDelegateErrorCodesV1,\n\tSubagentDelegateResultV1,\n\tSubagentDelegateRoleV1,\n\tSubagentDelegateTaskProjectionV1,\n\tSubagentDelegateTaskStatusV1,\n\tSubagentResultReadResultV1,\n\tSubagentRoleCatalogResolutionV1,\n\tSubagentRoleDefinitionViewV1,\n\tSubagentRoleListEntryV1,\n\tSubagentRoleListResultV1,\n\tSubagentRoleRemoveResultV1,\n\tSubagentRoleSetResultV1,\n\tSubagentRoleViewResultV1,\n\tSubagentSessionListEntryV1,\n\tSubagentSessionListResultV1,\n\tSubagentSessionRoleMergeV1,\n\tSubagentSessionRoleRecordV1,\n\tSubagentSessionRolesStateV1,\n} from \"./delegate.ts\";\nexport {\n\tcapabilityManifest,\n\tcreateCapability as createSubagentDelegateCapability,\n\tmergeSubagentRoles,\n\treadSessionRoles,\n\tresolveSubagentRoleCatalog,\n\tSESSION_ROLE_STATE_ENTRY,\n\tSubagentDelegateError,\n\tseedFactoryRoleCatalog,\n\tsubagentRoleCatalogPath,\n\ttoSessionRoleRecord,\n} from \"./delegate.ts\";\nexport type {\n\tAgentTaskErrorCodesV1,\n\tAgentTaskEventV1,\n\tAgentTaskRegistryOptionsV1,\n\tAgentTaskRegistryV1,\n\tAgentTaskStatusV1,\n\tAgentTaskV1,\n} from \"./multi-agent-tasks.ts\";\nexport {\n\tAgentTaskError,\n\tcreateAgentTaskRegistry,\n\treplayTaskLog,\n} from \"./multi-agent-tasks.ts\";\nexport { createRemoteAgentTaskAdapter } from \"./remote-adapter.ts\";\nexport type {\n\tSubagentRunnerPoolOptionsV1,\n\tSubagentRunnerPoolStatsV1,\n\tSubagentRunnerPoolV1,\n\tSubagentRunnerSpawnHandleV1,\n} from \"./runner-pool.ts\";\nexport {\n\tcreatePooledAgentTaskAdapterV1,\n\tSubagentRunnerPoolError,\n\tvalidateSubagentRunnerPoolOptionsV1,\n} from \"./runner-pool.ts\";\nexport type { NodeSubagentRunnerSpawnerOptionsV1 } from \"./runner-spawn.ts\";\nexport { createNodeSubagentRunnerSpawnerV1 } from \"./runner-spawn.ts\";\nexport type { AgentTaskSchedulerProviderOptionsV1 } from \"./scheduler-capability.ts\";\nexport {\n\tcreateAgentTaskSchedulerCapabilityProviderV1,\n\tprojectSchedulerResultV1,\n\tprojectSchedulerStatusV1,\n} from \"./scheduler-capability.ts\";\nexport type { SelfInvocationV1 } from \"./self-invocation.ts\";\nexport { resolveSelfInvocationV1 } from \"./self-invocation.ts\";\nexport { createAgentTaskApiAdapterV1 } from \"./shared-adapter.ts\";\nexport type {\n\tSchedulerTaskRecordV1,\n\tSubagentAdmissionGateV1,\n\tSubagentCancelByIdResultV1,\n\tSubagentRuntimeErrorCodesV1,\n\tSubagentRuntimeLimitsV1,\n\tSubagentRuntimeOptionsV1,\n\tSubagentRuntimeStatus,\n\tSubagentRuntimeSubmitRequestV1,\n\tSubagentRuntimeV1,\n\tSubagentTaskHandleV1,\n} from \"./subagent-runtime.ts\";\nexport {\n\tcreateSubagentRuntime,\n\tSubagentRuntimeError,\n\ttoAgentTaskStatusProjection,\n} from \"./subagent-runtime.ts\";\n"]}
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export { AgentTaskError, createAgentTaskRegistry, replayTaskLog, } from "./multi
16
16
  export { createRemoteAgentTaskAdapter } from "./remote-adapter.js";
17
17
  export { createPooledAgentTaskAdapterV1, SubagentRunnerPoolError, validateSubagentRunnerPoolOptionsV1, } from "./runner-pool.js";
18
18
  export { createNodeSubagentRunnerSpawnerV1 } from "./runner-spawn.js";
19
+ export { createAgentTaskSchedulerCapabilityProviderV1, projectSchedulerResultV1, projectSchedulerStatusV1, } from "./scheduler-capability.js";
19
20
  export { resolveSelfInvocationV1 } from "./self-invocation.js";
20
21
  export { createAgentTaskApiAdapterV1 } from "./shared-adapter.js";
21
22
  export { createSubagentRuntime, SubagentRuntimeError, toAgentTaskStatusProjection, } from "./subagent-runtime.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA+BH,OAAO,EACN,kBAAkB,EAClB,gBAAgB,IAAI,gCAAgC,EACpD,kBAAkB,EAClB,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,GACnB,MAAM,eAAe,CAAC;AASvB,OAAO,EACN,cAAc,EACd,uBAAuB,EACvB,aAAa,GACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAQnE,OAAO,EACN,8BAA8B,EAC9B,uBAAuB,EACvB,mCAAmC,GACnC,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAalE,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,2BAA2B,GAC3B,MAAM,uBAAuB,CAAC","sourcesContent":["/**\n * Subagent delegate capability plugin: the first production orchestrator over\n * the plugin-level `SubagentRuntime` (D-044), extracted from the host's\n * `src/capabilities/subagent-delegate.ts` (D-075 S4, third batch).\n *\n * Library face (`createSubagentDelegateCapability(api, options?)`) keeps the\n * explicit-options signature for in-package tests and third-party embedders;\n * the plugin entry (`./entry.ts`, manifest-loaded) assembles the same options\n * from the host services (`api.host`) and the agent-dir config channel. The\n * scheduler, runner pool, remote/shared adapters, multi-agent task registry\n * and self-invocation probe migrate with the capability and are re-exported\n * here so consumers keep one import face.\n */\n\n// 通信接线与信箱消息形状是 plugin-sdk 公共契约(D-075 S4 第三批迁入 SDK),此处再导出。\nexport type { SubagentCommunicationWiringV1, SubagentInboxMessageV1 } from \"@agent-forge/plugin-sdk\";\nexport type {\n\tSubagentCancelResultV1,\n\tSubagentDelegateBackgroundResultV1,\n\tSubagentDelegateBackgroundTaskV1,\n\tSubagentDelegateCapabilityOptions,\n\tSubagentDelegateContextAnchorV1,\n\tSubagentDelegateContextFailedAttemptV1,\n\tSubagentDelegateContextV1,\n\tSubagentDelegateErrorCodesV1,\n\tSubagentDelegateResultV1,\n\tSubagentDelegateRoleV1,\n\tSubagentDelegateTaskProjectionV1,\n\tSubagentDelegateTaskStatusV1,\n\tSubagentResultReadResultV1,\n\tSubagentRoleCatalogResolutionV1,\n\tSubagentRoleDefinitionViewV1,\n\tSubagentRoleListEntryV1,\n\tSubagentRoleListResultV1,\n\tSubagentRoleRemoveResultV1,\n\tSubagentRoleSetResultV1,\n\tSubagentRoleViewResultV1,\n\tSubagentSessionListEntryV1,\n\tSubagentSessionListResultV1,\n\tSubagentSessionRoleMergeV1,\n\tSubagentSessionRoleRecordV1,\n\tSubagentSessionRolesStateV1,\n} from \"./delegate.ts\";\nexport {\n\tcapabilityManifest,\n\tcreateCapability as createSubagentDelegateCapability,\n\tmergeSubagentRoles,\n\treadSessionRoles,\n\tresolveSubagentRoleCatalog,\n\tSESSION_ROLE_STATE_ENTRY,\n\tSubagentDelegateError,\n\tseedFactoryRoleCatalog,\n\tsubagentRoleCatalogPath,\n\ttoSessionRoleRecord,\n} from \"./delegate.ts\";\nexport type {\n\tAgentTaskErrorCodesV1,\n\tAgentTaskEventV1,\n\tAgentTaskRegistryOptionsV1,\n\tAgentTaskRegistryV1,\n\tAgentTaskStatusV1,\n\tAgentTaskV1,\n} from \"./multi-agent-tasks.ts\";\nexport {\n\tAgentTaskError,\n\tcreateAgentTaskRegistry,\n\treplayTaskLog,\n} from \"./multi-agent-tasks.ts\";\nexport { createRemoteAgentTaskAdapter } from \"./remote-adapter.ts\";\nexport type {\n\tSubagentRunnerPoolOptionsV1,\n\tSubagentRunnerPoolStatsV1,\n\tSubagentRunnerPoolV1,\n\tSubagentRunnerSpawnHandleV1,\n} from \"./runner-pool.ts\";\n\nexport {\n\tcreatePooledAgentTaskAdapterV1,\n\tSubagentRunnerPoolError,\n\tvalidateSubagentRunnerPoolOptionsV1,\n} from \"./runner-pool.ts\";\nexport type { NodeSubagentRunnerSpawnerOptionsV1 } from \"./runner-spawn.ts\";\n\nexport { createNodeSubagentRunnerSpawnerV1 } from \"./runner-spawn.ts\";\nexport type { SelfInvocationV1 } from \"./self-invocation.ts\";\nexport { resolveSelfInvocationV1 } from \"./self-invocation.ts\";\nexport { createAgentTaskApiAdapterV1 } from \"./shared-adapter.ts\";\nexport type {\n\tSchedulerTaskRecordV1,\n\tSubagentAdmissionGateV1,\n\tSubagentCancelByIdResultV1,\n\tSubagentRuntimeErrorCodesV1,\n\tSubagentRuntimeLimitsV1,\n\tSubagentRuntimeOptionsV1,\n\tSubagentRuntimeStatus,\n\tSubagentRuntimeSubmitRequestV1,\n\tSubagentRuntimeV1,\n\tSubagentTaskHandleV1,\n} from \"./subagent-runtime.ts\";\nexport {\n\tcreateSubagentRuntime,\n\tSubagentRuntimeError,\n\ttoAgentTaskStatusProjection,\n} from \"./subagent-runtime.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA+BH,OAAO,EACN,kBAAkB,EAClB,gBAAgB,IAAI,gCAAgC,EACpD,kBAAkB,EAClB,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,GACnB,MAAM,eAAe,CAAC;AASvB,OAAO,EACN,cAAc,EACd,uBAAuB,EACvB,aAAa,GACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAOnE,OAAO,EACN,8BAA8B,EAC9B,uBAAuB,EACvB,mCAAmC,GACnC,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EACN,4CAA4C,EAC5C,wBAAwB,EACxB,wBAAwB,GACxB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAalE,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,2BAA2B,GAC3B,MAAM,uBAAuB,CAAC","sourcesContent":["/**\n * Subagent delegate capability plugin: the first production orchestrator over\n * the plugin-level `SubagentRuntime` (D-044), extracted from the host's\n * `src/capabilities/subagent-delegate.ts` (D-075 S4, third batch).\n *\n * Library face (`createSubagentDelegateCapability(api, options?)`) keeps the\n * explicit-options signature for in-package tests and third-party embedders;\n * the plugin entry (`./entry.ts`, manifest-loaded) assembles the same options\n * from the host services (`api.host`) and the agent-dir config channel. The\n * scheduler, runner pool, remote/shared adapters, multi-agent task registry\n * and self-invocation probe migrate with the capability and are re-exported\n * here so consumers keep one import face.\n */\n\n// 通信接线与信箱消息形状是 plugin-sdk 公共契约(D-075 S4 第三批迁入 SDK),此处再导出。\nexport type { SubagentCommunicationWiringV1, SubagentInboxMessageV1 } from \"@agent-forge/plugin-sdk\";\nexport type {\n\tSubagentCancelResultV1,\n\tSubagentDelegateBackgroundResultV1,\n\tSubagentDelegateBackgroundTaskV1,\n\tSubagentDelegateCapabilityOptions,\n\tSubagentDelegateContextAnchorV1,\n\tSubagentDelegateContextFailedAttemptV1,\n\tSubagentDelegateContextV1,\n\tSubagentDelegateErrorCodesV1,\n\tSubagentDelegateResultV1,\n\tSubagentDelegateRoleV1,\n\tSubagentDelegateTaskProjectionV1,\n\tSubagentDelegateTaskStatusV1,\n\tSubagentResultReadResultV1,\n\tSubagentRoleCatalogResolutionV1,\n\tSubagentRoleDefinitionViewV1,\n\tSubagentRoleListEntryV1,\n\tSubagentRoleListResultV1,\n\tSubagentRoleRemoveResultV1,\n\tSubagentRoleSetResultV1,\n\tSubagentRoleViewResultV1,\n\tSubagentSessionListEntryV1,\n\tSubagentSessionListResultV1,\n\tSubagentSessionRoleMergeV1,\n\tSubagentSessionRoleRecordV1,\n\tSubagentSessionRolesStateV1,\n} from \"./delegate.ts\";\nexport {\n\tcapabilityManifest,\n\tcreateCapability as createSubagentDelegateCapability,\n\tmergeSubagentRoles,\n\treadSessionRoles,\n\tresolveSubagentRoleCatalog,\n\tSESSION_ROLE_STATE_ENTRY,\n\tSubagentDelegateError,\n\tseedFactoryRoleCatalog,\n\tsubagentRoleCatalogPath,\n\ttoSessionRoleRecord,\n} from \"./delegate.ts\";\nexport type {\n\tAgentTaskErrorCodesV1,\n\tAgentTaskEventV1,\n\tAgentTaskRegistryOptionsV1,\n\tAgentTaskRegistryV1,\n\tAgentTaskStatusV1,\n\tAgentTaskV1,\n} from \"./multi-agent-tasks.ts\";\nexport {\n\tAgentTaskError,\n\tcreateAgentTaskRegistry,\n\treplayTaskLog,\n} from \"./multi-agent-tasks.ts\";\nexport { createRemoteAgentTaskAdapter } from \"./remote-adapter.ts\";\nexport type {\n\tSubagentRunnerPoolOptionsV1,\n\tSubagentRunnerPoolStatsV1,\n\tSubagentRunnerPoolV1,\n\tSubagentRunnerSpawnHandleV1,\n} from \"./runner-pool.ts\";\nexport {\n\tcreatePooledAgentTaskAdapterV1,\n\tSubagentRunnerPoolError,\n\tvalidateSubagentRunnerPoolOptionsV1,\n} from \"./runner-pool.ts\";\nexport type { NodeSubagentRunnerSpawnerOptionsV1 } from \"./runner-spawn.ts\";\nexport { createNodeSubagentRunnerSpawnerV1 } from \"./runner-spawn.ts\";\nexport type { AgentTaskSchedulerProviderOptionsV1 } from \"./scheduler-capability.ts\";\nexport {\n\tcreateAgentTaskSchedulerCapabilityProviderV1,\n\tprojectSchedulerResultV1,\n\tprojectSchedulerStatusV1,\n} from \"./scheduler-capability.ts\";\nexport type { SelfInvocationV1 } from \"./self-invocation.ts\";\nexport { resolveSelfInvocationV1 } from \"./self-invocation.ts\";\nexport { createAgentTaskApiAdapterV1 } from \"./shared-adapter.ts\";\nexport type {\n\tSchedulerTaskRecordV1,\n\tSubagentAdmissionGateV1,\n\tSubagentCancelByIdResultV1,\n\tSubagentRuntimeErrorCodesV1,\n\tSubagentRuntimeLimitsV1,\n\tSubagentRuntimeOptionsV1,\n\tSubagentRuntimeStatus,\n\tSubagentRuntimeSubmitRequestV1,\n\tSubagentRuntimeV1,\n\tSubagentTaskHandleV1,\n} from \"./subagent-runtime.ts\";\nexport {\n\tcreateSubagentRuntime,\n\tSubagentRuntimeError,\n\ttoAgentTaskStatusProjection,\n} from \"./subagent-runtime.ts\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"remote-adapter.d.ts","sourceRoot":"","sources":["../src/remote-adapter.ts"],"names":[],"mappings":"AAeA,OAAO,EAKN,KAAK,gBAAgB,EAKrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGN,KAAK,qBAAqB,EAG1B,KAAK,6BAA6B,EAElC,MAAM,gCAAgC,CAAC;AAgRxC;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,qBAAqB,GAC5B,gBAAgB,GAAG,6BAA6B,CAgGlD","sourcesContent":["/**\n * subagent-task 远程 adapter(D-045 / pooled 切片第 1 增量)。\n *\n * `AgentTaskAdapter` 的跨进程实现:经 `SubagentTaskChannelV1` 与 runner 侧\n * server 对话(create/run/cancel/dispose/result)。run 语义与本地一致——\n * `host.run()` resolve = 该次 prompt 完成(aborted 是正常结果);signal 中止\n * 时发 cancel 并等待 run 终态。`session.getMessages()` 为同步签名,消息在\n * run 终态时经 result op 预取缓存。本文件不做进程 spawn(runner 生命周期属\n * pooled 切片第 2 增量)。\n *\n * 迁自宿主 `src/plugins/subagent-task/remote-adapter.ts`(D-075 S4 第三批);公共契约\n * 改自 plugin-sdk,wire 协议/进度/server 事实类型改自 @agent-forge/protocol(宿主侧\n * 同名模块已下沉该包)。\n */\nimport { randomUUID } from \"node:crypto\";\nimport {\n\tAGENT_TASK_CHILD_PROFILE_KEY,\n\tAGENT_TASK_PARENT_SESSION_KEY,\n\tAGENT_TASK_PARENT_TRACE_KEY,\n\tAGENT_TASK_RESUME_SESSION_KEY,\n\ttype AgentTaskAdapter,\n\ttype AgentTaskCreateRequest,\n\ttype AgentTaskHost,\n\ttype ModelFactsViewV1,\n\ttype SessionAPI,\n} from \"@agent-forge/plugin-sdk\";\nimport {\n\tSUBAGENT_TASK_PROTOCOL_VERSION,\n\ttype SubagentTaskAppliedProfileV1,\n\ttype SubagentTaskChannelV1,\n\ttype SubagentTaskEnvelopeV1,\n\ttype SubagentTaskOkResponseEnvelopeV1,\n\ttype SubagentTaskProgressAdapterV1,\n\tSubagentTaskProtocolError,\n} from \"@agent-forge/protocol/subagent\";\n\ninterface PendingRequest {\n\tresolve(env: SubagentTaskOkResponseEnvelopeV1): void;\n\treject(error: SubagentTaskProtocolError): void;\n}\n\n/** 与本地 SDK adapter 相同的取消原因规范化:非字符串 reason 记为 \"cancelled\"。 */\nfunction abortReasonText(signal: AbortSignal): string {\n\treturn typeof signal.reason === \"string\" ? signal.reason : \"cancelled\";\n}\n\n/** 身份违规(跨任务应答):一律硬失败,绝不降级成\"拿不到结果\"。 */\nfunction isCrossTaskViolation(error: unknown): boolean {\n\treturn typeof error === \"object\" && error !== null && (error as { code?: unknown }).code === \"cross_task_response\";\n}\n\n/** 与 sdk.ts abortError 同形的取消类错误:name=\"AbortError\",由 guards 归到 cancelled。 */\nfunction abortLikeError(message: string): Error {\n\tconst error = new Error(message);\n\terror.name = \"AbortError\";\n\treturn error;\n}\n\n/**\n * 远程 host.session 只实现调度路径实际消费的面:getSessionId/getMessages\n * (run 终态时预取的有界快照)/isIdle/abort(映射为 cancel)/waitForIdle。\n * prompt 为桩——远程路径经 host.run 走 run op,不支持对 remote session 直接\n * prompt。桩边界以 docs/design/子代理pooled切片与Agent服务协议边界设计.md §4 为准。\n */\n\nfunction createRemoteSessionProxy(taskId: string, client: RemoteTaskClient, agentSessionId?: string): SessionAPI {\n\t// 远程调度路径不使用的 SessionAPI 成员:显式桩(抛协议错误),不静默返回假数据。\n\tconst unsupportedAsync = (name: string): (() => Promise<never>) => {\n\t\treturn async () => {\n\t\t\tthrow new SubagentTaskProtocolError(`remote session does not support ${name}`);\n\t\t};\n\t};\n\tconst unsupportedSync = (name: string): (() => never) => {\n\t\treturn () => {\n\t\t\tthrow new SubagentTaskProtocolError(`remote session does not support ${name}`);\n\t\t};\n\t};\n\treturn {\n\t\tgetSessionId: () => taskId,\n\t\t// 叶子会话自身身份:父侧记录与回读用它(而不是 wire 任务 id)。\n\t\t...(agentSessionId === undefined ? {} : { getAgentSessionId: () => agentSessionId }),\n\t\tgetMessages: () => client.cachedMessages(taskId),\n\t\tisIdle: () => !client.hasActiveRun(taskId),\n\t\tprompt: unsupportedAsync(\"direct prompt; use AgentTaskHost.run\"),\n\t\tabort: () => client.cancelTask(taskId, \"session abort\"),\n\t\twaitForIdle: () => client.waitForIdle(taskId),\n\t\tappendEntry: unsupportedSync(\"appendEntry\"),\n\t\tgetBranchEntries: unsupportedSync(\"getBranchEntries\"),\n\t\t// 事实面(runner 自报):档案核验需要它们。runner 未回事实时**不声明**这些成员——\n\t\t// 上层因此看到\"宿主不暴露事实\"并按无法自证处理,而不是被空数组糊弄成通过。\n\t\t...(client.appliedProfile(taskId)?.activeTools === undefined\n\t\t\t? {}\n\t\t\t: { getActiveTools: (): string[] => [...(client.appliedProfile(taskId)?.activeTools ?? [])] }),\n\t\t...(client.appliedProfile(taskId)?.model === undefined\n\t\t\t? {}\n\t\t\t: { getModel: (): ModelFactsViewV1 => ({ ...(client.appliedProfile(taskId)?.model as ModelFactsViewV1) }) }),\n\t\t// 父→子引导(D-060 S5 pooled parity):经 wire steer op 到叶子会话自身 steer。\n\t\tsteer: (text: string) => client.steerTask(taskId, text),\n\t};\n}\n\nclass RemoteTaskClient {\n\tprivate readonly channel: SubagentTaskChannelV1;\n\tprivate requestSequence = 0;\n\tprivate readonly pending = new Map<string, PendingRequest>();\n\tprivate readonly taskProgressListeners = new Map<string, Set<(message: string | undefined, seq: number) => void>>();\n\tprivate readonly activeRuns = new Map<string, number>();\n\t/** 每个任务当前 run 的 runId:进度事件按此校验,陈旧或串台 run 的进度不得投递。 */\n\tprivate readonly activeRunIds = new Map<string, string>();\n\tprivate readonly idleWaiters = new Map<string, Array<() => void>>();\n\tprivate readonly messageCache = new Map<string, readonly unknown[]>();\n\t/** create 应答里 runner 自报的收窄事实(工具面/模型/模式):代理据此暴露可核验面。 */\n\tprivate readonly appliedProfiles = new Map<string, SubagentTaskAppliedProfileV1>();\n\tprivate reader: Promise<void> | undefined;\n\tprivate closed = false;\n\n\tconstructor(channel: SubagentTaskChannelV1) {\n\t\tthis.channel = channel;\n\t}\n\n\tstart(): void {\n\t\tif (this.reader !== undefined) return;\n\t\tthis.reader = (async () => {\n\t\t\ttry {\n\t\t\t\tfor await (const env of this.channel) {\n\t\t\t\t\tthis.dispatch(env);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.failAllPending(error instanceof Error ? error : new SubagentTaskProtocolError(\"channel read failed\"));\n\t\t\t}\n\t\t\t// 通道关闭 = 对端(runner 进程)已消失:在途任务按 runner_lost 结算,\n\t\t\t// 由调度器投影为 failed + reasonCode subagent_runner_lost(D-044 §4.3)。\n\t\t\tthis.failAllPending(new SubagentTaskProtocolError(\"subagent runner lost: channel closed\", \"runner_lost\"));\n\t\t})();\n\t\tvoid this.reader.catch(() => {});\n\t}\n\n\tprivate dispatch(env: SubagentTaskEnvelopeV1): void {\n\t\tif (env.kind === \"response\") {\n\t\t\tconst pending = this.pending.get(env.id);\n\t\t\tif (pending === undefined) return; // 未知响应:丢弃(迟到回执)\n\t\t\tthis.pending.delete(env.id);\n\t\t\tif (env.ok) pending.resolve(env);\n\t\t\telse pending.reject(new SubagentTaskProtocolError(env.message, env.code));\n\t\t\treturn;\n\t\t}\n\t\tif (env.kind === \"event\") {\n\t\t\t// 隔离校验:只有\"该任务当前 run\"的进度才投递。runner 侧陈旧批次、\n\t\t\t// 或身份错标(B 任务的进度挂在 A 的 taskId 上)一律丢弃,宁可少一条\n\t\t\t// 提示也不让父侧把别的子会话的进度算到当前任务上。\n\t\t\tconst expectedRunId = this.activeRunIds.get(env.taskId);\n\t\t\tif (expectedRunId === undefined || env.runId !== expectedRunId) return;\n\t\t\tconst taskListeners = this.taskProgressListeners.get(env.taskId);\n\t\t\tif (taskListeners !== undefined) {\n\t\t\t\tfor (const listener of taskListeners) listener(env.message, env.seq);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate failAllPending(error: SubagentTaskProtocolError): void {\n\t\tthis.closed = true;\n\t\tfor (const pending of this.pending.values()) pending.reject(error);\n\t\tthis.pending.clear();\n\t}\n\n\tcall(\n\t\trequest: Omit<Extract<SubagentTaskEnvelopeV1, { kind: \"request\" }>, \"v\" | \"kind\" | \"id\">,\n\t): Promise<SubagentTaskOkResponseEnvelopeV1> {\n\t\t// 通道已关闭后不再入队:立即 reject,避免调用方永久悬挂。\n\t\tif (this.closed) {\n\t\t\treturn Promise.reject(new SubagentTaskProtocolError(\"subagent runner lost: channel closed\", \"runner_lost\"));\n\t\t}\n\t\tthis.start();\n\t\tconst id = `req:${++this.requestSequence}:${randomUUID().slice(0, 8)}`;\n\t\treturn new Promise<SubagentTaskOkResponseEnvelopeV1>((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve, reject });\n\t\t\tvoid this.channel.write({ v: SUBAGENT_TASK_PROTOCOL_VERSION, kind: \"request\", id, ...request });\n\t\t});\n\t}\n\n\t/**\n\t * 任务作用域调用:请求与应答必须是同一个任务。runner 若就 A 的请求回 B 的\n\t * taskId/runId(身份错标、状态错位),这里按 `cross_task_response` 硬失败,\n\t * 绝不把别的子会话的消息缓存成 A 的结果。\n\t */\n\tasync callForTask(\n\t\ttaskId: string,\n\t\trequest: Omit<Extract<SubagentTaskEnvelopeV1, { kind: \"request\" }>, \"v\" | \"kind\" | \"id\" | \"taskId\">,\n\t\trunId?: string,\n\t): Promise<SubagentTaskOkResponseEnvelopeV1> {\n\t\tconst response = await this.call({ ...request, taskId, ...(runId === undefined ? {} : { runId }) });\n\t\tif (response.taskId !== taskId) {\n\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t`runner answered task ${String(response.taskId)} for a task ${taskId} request`,\n\t\t\t\t\"cross_task_response\",\n\t\t\t);\n\t\t}\n\t\tif (runId !== undefined && response.runId !== runId) {\n\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t`runner answered run ${String(response.runId)} for a run ${runId} request`,\n\t\t\t\t\"cross_task_response\",\n\t\t\t);\n\t\t}\n\t\treturn response;\n\t}\n\n\t/** 订阅某个任务(wire taskId)的进度事件;返回退订函数。 */\n\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\tconst listeners = this.taskProgressListeners.get(taskId);\n\t\tif (listeners === undefined) this.taskProgressListeners.set(taskId, new Set([listener]));\n\t\telse listeners.add(listener);\n\t\treturn () => {\n\t\t\tconst current = this.taskProgressListeners.get(taskId);\n\t\t\tif (current === undefined) return;\n\t\t\tcurrent.delete(listener);\n\t\t\tif (current.size === 0) this.taskProgressListeners.delete(taskId);\n\t\t};\n\t}\n\n\t/** 登记 in-flight run 并接管 signal→cancel 级联;释放必须经 releaseRun。 */\n\ttrackRun(taskId: string, runId: string, signal: AbortSignal): void {\n\t\tthis.activeRuns.set(taskId, (this.activeRuns.get(taskId) ?? 0) + 1);\n\t\tthis.activeRunIds.set(taskId, runId);\n\t\t// 一次 run 至多挂一个 abort 监听;server 侧 cancel 幂等,重复触发无害。\n\t\tsignal.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tvoid this.cancelTask(taskId, abortReasonText(signal)).catch(() => {});\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t/** run 终态(resolve 或 reject)后调用:递减活跃计数并唤醒 waitForIdle。 */\n\treleaseRun(taskId: string, runId?: string): void {\n\t\tconst current = this.activeRuns.get(taskId) ?? 0;\n\t\tif (current <= 1) {\n\t\t\tthis.activeRuns.delete(taskId);\n\t\t\t// 仅释放属于该 run 的 runId 槽:并发的同名释放不会顶掉新 run 的登记。\n\t\t\tif (runId === undefined || this.activeRunIds.get(taskId) === runId) {\n\t\t\t\tthis.activeRunIds.delete(taskId);\n\t\t\t}\n\t\t\tthis.wakeIdle(taskId);\n\t\t\treturn;\n\t\t}\n\t\tthis.activeRuns.set(taskId, current - 1);\n\t}\n\n\thasActiveRun(taskId: string): boolean {\n\t\treturn (this.activeRuns.get(taskId) ?? 0) > 0;\n\t}\n\n\twaitForIdle(taskId: string): Promise<void> {\n\t\tif (!this.hasActiveRun(taskId)) return Promise.resolve();\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst waiters = this.idleWaiters.get(taskId);\n\t\t\tif (waiters === undefined) this.idleWaiters.set(taskId, [resolve]);\n\t\t\telse waiters.push(resolve);\n\t\t});\n\t}\n\n\tprivate wakeIdle(taskId: string): void {\n\t\tfor (const wake of this.idleWaiters.get(taskId)?.splice(0) ?? []) wake();\n\t}\n\n\tasync refreshMessages(taskId: string): Promise<void> {\n\t\tconst response = await this.callForTask(taskId, { op: \"result\" });\n\t\tthis.messageCache.set(taskId, response.messages ?? []);\n\t}\n\n\tcachedMessages(taskId: string): readonly unknown[] {\n\t\treturn this.messageCache.get(taskId) ?? [];\n\t}\n\n\t/**\n\t * 释放某任务的缓存:终态后消息快照与进度订阅都不再需要,长寿命 runner 连接\n\t * 不能按任务数无界增长(每条快照上限是 settle 预算)。释放顺序由调度器保证:\n\t * settle 先读 getMessages,再调用 host.dispose。\n\t */\n\tdropTask(taskId: string): void {\n\t\tthis.messageCache.delete(taskId);\n\t\tthis.taskProgressListeners.delete(taskId);\n\t\tthis.activeRunIds.delete(taskId);\n\t\tthis.appliedProfiles.delete(taskId);\n\t}\n\n\t/** 记录 runner 自报的档案事实(create 应答)。 */\n\trememberAppliedProfile(taskId: string, applied: SubagentTaskAppliedProfileV1 | undefined): void {\n\t\tif (applied === undefined) return;\n\t\tthis.appliedProfiles.set(taskId, applied);\n\t}\n\n\tappliedProfile(taskId: string): SubagentTaskAppliedProfileV1 | undefined {\n\t\treturn this.appliedProfiles.get(taskId);\n\t}\n\n\tasync cancelTask(taskId: string, reason?: string): Promise<void> {\n\t\tawait this.callForTask(taskId, { op: \"cancel\", ...(reason === undefined ? {} : { reason }) });\n\t}\n\n\t/** 父→子引导(D-060 S5 pooled parity):steer op 到 runner 叶子会话。 */\n\tasync steerTask(taskId: string, text: string): Promise<void> {\n\t\tawait this.callForTask(taskId, { op: \"steer\", text });\n\t}\n}\n\n/**\n * 远程 `AgentTaskAdapter`:与本地 SDK adapter 语义对齐——create 分配 runner 侧\n * 会话;run resolve = prompt 完成,`aborted` 终局抛 `AbortError` 类取消错误\n * (与 sdk.ts 的 aborted PromptOutcome 处理一致,由 guards 归到 cancelled,\n * 不得落成 succeeded);cancel 幂等;dispose 释放。channel 关闭或读失败时\n * 全部在途请求 reject(保留错误码),关闭后的新请求立即 reject 不悬挂。\n */\nexport function createRemoteAgentTaskAdapter(\n\tchannel: SubagentTaskChannelV1,\n): AgentTaskAdapter & SubagentTaskProgressAdapterV1 {\n\tconst client = new RemoteTaskClient(channel);\n\tconst liveTaskIds = new Set<string>();\n\treturn {\n\t\t/** D-044 §5.6:把 runner 侧的 progress 事件按 wire taskId 转给上层订阅者。 */\n\t\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\t\treturn client.onTaskProgress(taskId, listener);\n\t\t},\n\t\tcreate: async (request: AgentTaskCreateRequest): Promise<AgentTaskHost> => {\n\t\t\t// 子任务档案随 create 过线:runner 侧叶子会话按它收窄,并在应答里回实际事实。\n\t\t\tconst profile = request.metadata?.[AGENT_TASK_CHILD_PROFILE_KEY];\n\t\t\tconst parentSessionId = request.metadata?.[AGENT_TASK_PARENT_SESSION_KEY];\n\t\t\t// resume 目标(D-060 S5 pooled parity):runner 打开既有会话文件续写,不新建。\n\t\t\tconst resumeSessionId = request.metadata?.[AGENT_TASK_RESUME_SESSION_KEY];\n\t\t\t// 回合级血缘(第 3 期第二批):创建子会话的父回合 correlationId,仅 create 新建消费。\n\t\t\tconst parentTraceId = request.metadata?.[AGENT_TASK_PARENT_TRACE_KEY];\n\t\t\tconst created = await client.call({\n\t\t\t\top: \"create\",\n\t\t\t\tprompt: request.prompt,\n\t\t\t\t...(profile === undefined ? {} : { profile }),\n\t\t\t\t...(typeof parentSessionId === \"string\" ? { parentSessionId } : {}),\n\t\t\t\t...(typeof resumeSessionId === \"string\" ? { resumeSessionId } : {}),\n\t\t\t\t...(typeof parentTraceId === \"string\" ? { parentTraceId } : {}),\n\t\t\t});\n\t\t\tconst taskId = created.taskId;\n\t\t\tif (taskId === undefined) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\"create response missing taskId\", \"invalid_request\");\n\t\t\t}\n\t\t\t// 任务 id 必须唯一:runner 若把已存活任务的 id 再发一次,就是身份复用,\n\t\t\t// 之后两个任务的应答将无法区分——直接硬失败而不是继续跑。\n\t\t\tif (liveTaskIds.has(taskId)) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t\t`runner reused the id of a live task: ${taskId}`,\n\t\t\t\t\t\"cross_task_response\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tliveTaskIds.add(taskId);\n\t\t\tclient.rememberAppliedProfile(taskId, created.appliedProfile);\n\t\t\t// 叶子会话自身的 sessionId(D-060 S1):宿主可见的 getSessionId() 是 wire 任务 id,\n\t\t\t// 真正的 agent 会话 id 走 getAgentSessionId 暴露。\n\t\t\tconst agentSessionId = created.sessionId;\n\t\t\tconst host: AgentTaskHost = {\n\t\t\t\tsession: createRemoteSessionProxy(taskId, client, agentSessionId),\n\t\t\t\trun: (prompt: string, signal: AbortSignal): Promise<void> => {\n\t\t\t\t\tconst runId = `run:${randomUUID().slice(0, 8)}`;\n\t\t\t\t\tif (signal.aborted) {\n\t\t\t\t\t\t// 与本地 SDK adapter 一致:入口即中止只本地拒绝,不向 runner 发取消——\n\t\t\t\t\t\t// 什么都没有启动,任务保持可用(发取消会把任务标记为终态)。\n\t\t\t\t\t\treturn Promise.reject(abortLikeError(`run aborted before start: ${abortReasonText(signal)}`));\n\t\t\t\t\t}\n\t\t\t\t\tclient.trackRun(taskId, runId, signal);\n\t\t\t\t\treturn client\n\t\t\t\t\t\t.callForTask(taskId, { op: \"run\", prompt }, runId)\n\t\t\t\t\t\t.then(async (response) => {\n\t\t\t\t\t\t\t// run 终态后预取有界消息,供调度器 settle 同步读取。\n\t\t\t\t\t\t\t// 预取失败本身可容忍(拿不到消息不等于任务失败),但身份违规不可\n\t\t\t\t\t\t\t// 容忍:那是 runner 把别的任务的消息算到了这个任务上。\n\t\t\t\t\t\t\tawait client.refreshMessages(taskId).catch((error: unknown) => {\n\t\t\t\t\t\t\t\tif (isCrossTaskViolation(error)) throw error;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (response.status === \"cancelled\") {\n\t\t\t\t\t\t\t\tthrow abortLikeError(\"agent task run was cancelled\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\t\t// 取消先于 run 到达:runner 以 task_terminal 拒绝启动。父侧确实请求过取消,\n\t\t\t\t\t\t\t// 因此仍按取消类错误结算(与\"aborted 终局\"同一分类),不落成 failed。\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tsignal.aborted &&\n\t\t\t\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t\t\t(error as { code?: unknown }).code === \"task_terminal\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow abortLikeError(`agent task run was cancelled before start: ${abortReasonText(signal)}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.finally(() => client.releaseRun(taskId, runId));\n\t\t\t\t},\n\t\t\t\tcancel: (reason?: string): Promise<void> => client.cancelTask(taskId, reason),\n\t\t\t\tdispose: async (): Promise<void> => {\n\t\t\t\t\tliveTaskIds.delete(taskId);\n\t\t\t\t\tawait client.callForTask(taskId, { op: \"dispose\" });\n\t\t\t\t\tclient.dropTask(taskId);\n\t\t\t\t},\n\t\t\t};\n\t\t\treturn host;\n\t\t},\n\t\tdispose: async (): Promise<void> => {\n\t\t\t// 宿主会话销毁时释放全部未 dispose 的任务(逐个容错,不阻断其余回收)。\n\t\t\tfor (const taskId of [...liveTaskIds]) {\n\t\t\t\tliveTaskIds.delete(taskId);\n\t\t\t\tawait client.callForTask(taskId, { op: \"dispose\" }).catch(() => {});\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"remote-adapter.d.ts","sourceRoot":"","sources":["../src/remote-adapter.ts"],"names":[],"mappings":"AAeA,OAAO,EAKN,KAAK,gBAAgB,EAKrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGN,KAAK,qBAAqB,EAG1B,KAAK,6BAA6B,EAElC,MAAM,gCAAgC,CAAC;AAqRxC;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,qBAAqB,GAC5B,gBAAgB,GAAG,6BAA6B,CAgGlD","sourcesContent":["/**\n * subagent-task 远程 adapter(D-045 / pooled 切片第 1 增量)。\n *\n * `AgentTaskAdapter` 的跨进程实现:经 `SubagentTaskChannelV1` 与 runner 侧\n * server 对话(create/run/cancel/dispose/result)。run 语义与本地一致——\n * `host.run()` resolve = 该次 prompt 完成(aborted 是正常结果);signal 中止\n * 时发 cancel 并等待 run 终态。`session.getMessages()` 为同步签名,消息在\n * run 终态时经 result op 预取缓存。本文件不做进程 spawn(runner 生命周期属\n * pooled 切片第 2 增量)。\n *\n * 迁自宿主 `src/plugins/subagent-task/remote-adapter.ts`(D-075 S4 第三批);公共契约\n * 改自 plugin-sdk,wire 协议/进度/server 事实类型改自 @agent-forge/protocol(宿主侧\n * 同名模块已下沉该包)。\n */\nimport { randomUUID } from \"node:crypto\";\nimport {\n\tAGENT_TASK_CHILD_PROFILE_KEY,\n\tAGENT_TASK_PARENT_SESSION_KEY,\n\tAGENT_TASK_PARENT_TRACE_KEY,\n\tAGENT_TASK_RESUME_SESSION_KEY,\n\ttype AgentTaskAdapter,\n\ttype AgentTaskCreateRequest,\n\ttype AgentTaskHost,\n\ttype ModelFactsViewV1,\n\ttype SessionAPI,\n} from \"@agent-forge/plugin-sdk\";\nimport {\n\tSUBAGENT_TASK_PROTOCOL_VERSION,\n\ttype SubagentTaskAppliedProfileV1,\n\ttype SubagentTaskChannelV1,\n\ttype SubagentTaskEnvelopeV1,\n\ttype SubagentTaskOkResponseEnvelopeV1,\n\ttype SubagentTaskProgressAdapterV1,\n\tSubagentTaskProtocolError,\n} from \"@agent-forge/protocol/subagent\";\n\ninterface PendingRequest {\n\tresolve(env: SubagentTaskOkResponseEnvelopeV1): void;\n\treject(error: SubagentTaskProtocolError): void;\n}\n\n/** 与本地 SDK adapter 相同的取消原因规范化:非字符串 reason 记为 \"cancelled\"。 */\nfunction abortReasonText(signal: AbortSignal): string {\n\treturn typeof signal.reason === \"string\" ? signal.reason : \"cancelled\";\n}\n\n/** 身份违规(跨任务应答):一律硬失败,绝不降级成\"拿不到结果\"。 */\nfunction isCrossTaskViolation(error: unknown): boolean {\n\treturn typeof error === \"object\" && error !== null && (error as { code?: unknown }).code === \"cross_task_response\";\n}\n\n/** 与 sdk.ts abortError 同形的取消类错误:name=\"AbortError\",由 guards 归到 cancelled。 */\nfunction abortLikeError(message: string): Error {\n\tconst error = new Error(message);\n\terror.name = \"AbortError\";\n\treturn error;\n}\n\n/**\n * 远程 host.session 只实现调度路径实际消费的面:getSessionId/getMessages\n * (run 终态时预取的有界快照)/isIdle/abort(映射为 cancel)/waitForIdle。\n * prompt 为桩——远程路径经 host.run 走 run op,不支持对 remote session 直接\n * prompt。桩边界以 docs/design/子代理pooled切片与Agent服务协议边界设计.md §4 为准。\n */\n\nfunction createRemoteSessionProxy(taskId: string, client: RemoteTaskClient, agentSessionId?: string): SessionAPI {\n\t// 远程调度路径不使用的 SessionAPI 成员:显式桩(抛协议错误),不静默返回假数据。\n\tconst unsupportedAsync = (name: string): (() => Promise<never>) => {\n\t\treturn async () => {\n\t\t\tthrow new SubagentTaskProtocolError(`remote session does not support ${name}`);\n\t\t};\n\t};\n\tconst unsupportedSync = (name: string): (() => never) => {\n\t\treturn () => {\n\t\t\tthrow new SubagentTaskProtocolError(`remote session does not support ${name}`);\n\t\t};\n\t};\n\treturn {\n\t\tgetSessionId: () => taskId,\n\t\t// 叶子会话自身身份:父侧记录与回读用它(而不是 wire 任务 id)。\n\t\t...(agentSessionId === undefined ? {} : { getAgentSessionId: () => agentSessionId }),\n\t\tgetMessages: () => client.cachedMessages(taskId),\n\t\tisIdle: () => !client.hasActiveRun(taskId),\n\t\tprompt: unsupportedAsync(\"direct prompt; use AgentTaskHost.run\"),\n\t\tabort: () => client.cancelTask(taskId, \"session abort\"),\n\t\twaitForIdle: () => client.waitForIdle(taskId),\n\t\tappendEntry: unsupportedSync(\"appendEntry\"),\n\t\tgetBranchEntries: unsupportedSync(\"getBranchEntries\"),\n\t\t// 事实面(runner 自报):档案核验需要它们。runner 未回事实时**不声明**这些成员——\n\t\t// 上层因此看到\"宿主不暴露事实\"并按无法自证处理,而不是被空数组糊弄成通过。\n\t\t...(client.appliedProfile(taskId)?.activeTools === undefined\n\t\t\t? {}\n\t\t\t: { getActiveTools: (): string[] => [...(client.appliedProfile(taskId)?.activeTools ?? [])] }),\n\t\t...(client.appliedProfile(taskId)?.model === undefined\n\t\t\t? {}\n\t\t\t: { getModel: (): ModelFactsViewV1 => ({ ...(client.appliedProfile(taskId)?.model as ModelFactsViewV1) }) }),\n\t\t// P2 parity: the runner echoes the applied web-search mode; the parent-side\n\t\t// profile verification reads it through the same facts face as tools/model.\n\t\t...(client.appliedProfile(taskId)?.webSearch === undefined\n\t\t\t? {}\n\t\t\t: { getWebSearch: (): \"off\" | \"auto\" => client.appliedProfile(taskId)?.webSearch ?? \"off\" }),\n\t\t// 父→子引导(D-060 S5 pooled parity):经 wire steer op 到叶子会话自身 steer。\n\t\tsteer: (text: string) => client.steerTask(taskId, text),\n\t};\n}\n\nclass RemoteTaskClient {\n\tprivate readonly channel: SubagentTaskChannelV1;\n\tprivate requestSequence = 0;\n\tprivate readonly pending = new Map<string, PendingRequest>();\n\tprivate readonly taskProgressListeners = new Map<string, Set<(message: string | undefined, seq: number) => void>>();\n\tprivate readonly activeRuns = new Map<string, number>();\n\t/** 每个任务当前 run 的 runId:进度事件按此校验,陈旧或串台 run 的进度不得投递。 */\n\tprivate readonly activeRunIds = new Map<string, string>();\n\tprivate readonly idleWaiters = new Map<string, Array<() => void>>();\n\tprivate readonly messageCache = new Map<string, readonly unknown[]>();\n\t/** create 应答里 runner 自报的收窄事实(工具面/模型/模式):代理据此暴露可核验面。 */\n\tprivate readonly appliedProfiles = new Map<string, SubagentTaskAppliedProfileV1>();\n\tprivate reader: Promise<void> | undefined;\n\tprivate closed = false;\n\n\tconstructor(channel: SubagentTaskChannelV1) {\n\t\tthis.channel = channel;\n\t}\n\n\tstart(): void {\n\t\tif (this.reader !== undefined) return;\n\t\tthis.reader = (async () => {\n\t\t\ttry {\n\t\t\t\tfor await (const env of this.channel) {\n\t\t\t\t\tthis.dispatch(env);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.failAllPending(error instanceof Error ? error : new SubagentTaskProtocolError(\"channel read failed\"));\n\t\t\t}\n\t\t\t// 通道关闭 = 对端(runner 进程)已消失:在途任务按 runner_lost 结算,\n\t\t\t// 由调度器投影为 failed + reasonCode subagent_runner_lost(D-044 §4.3)。\n\t\t\tthis.failAllPending(new SubagentTaskProtocolError(\"subagent runner lost: channel closed\", \"runner_lost\"));\n\t\t})();\n\t\tvoid this.reader.catch(() => {});\n\t}\n\n\tprivate dispatch(env: SubagentTaskEnvelopeV1): void {\n\t\tif (env.kind === \"response\") {\n\t\t\tconst pending = this.pending.get(env.id);\n\t\t\tif (pending === undefined) return; // 未知响应:丢弃(迟到回执)\n\t\t\tthis.pending.delete(env.id);\n\t\t\tif (env.ok) pending.resolve(env);\n\t\t\telse pending.reject(new SubagentTaskProtocolError(env.message, env.code));\n\t\t\treturn;\n\t\t}\n\t\tif (env.kind === \"event\") {\n\t\t\t// 隔离校验:只有\"该任务当前 run\"的进度才投递。runner 侧陈旧批次、\n\t\t\t// 或身份错标(B 任务的进度挂在 A 的 taskId 上)一律丢弃,宁可少一条\n\t\t\t// 提示也不让父侧把别的子会话的进度算到当前任务上。\n\t\t\tconst expectedRunId = this.activeRunIds.get(env.taskId);\n\t\t\tif (expectedRunId === undefined || env.runId !== expectedRunId) return;\n\t\t\tconst taskListeners = this.taskProgressListeners.get(env.taskId);\n\t\t\tif (taskListeners !== undefined) {\n\t\t\t\tfor (const listener of taskListeners) listener(env.message, env.seq);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate failAllPending(error: SubagentTaskProtocolError): void {\n\t\tthis.closed = true;\n\t\tfor (const pending of this.pending.values()) pending.reject(error);\n\t\tthis.pending.clear();\n\t}\n\n\tcall(\n\t\trequest: Omit<Extract<SubagentTaskEnvelopeV1, { kind: \"request\" }>, \"v\" | \"kind\" | \"id\">,\n\t): Promise<SubagentTaskOkResponseEnvelopeV1> {\n\t\t// 通道已关闭后不再入队:立即 reject,避免调用方永久悬挂。\n\t\tif (this.closed) {\n\t\t\treturn Promise.reject(new SubagentTaskProtocolError(\"subagent runner lost: channel closed\", \"runner_lost\"));\n\t\t}\n\t\tthis.start();\n\t\tconst id = `req:${++this.requestSequence}:${randomUUID().slice(0, 8)}`;\n\t\treturn new Promise<SubagentTaskOkResponseEnvelopeV1>((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve, reject });\n\t\t\tvoid this.channel.write({ v: SUBAGENT_TASK_PROTOCOL_VERSION, kind: \"request\", id, ...request });\n\t\t});\n\t}\n\n\t/**\n\t * 任务作用域调用:请求与应答必须是同一个任务。runner 若就 A 的请求回 B 的\n\t * taskId/runId(身份错标、状态错位),这里按 `cross_task_response` 硬失败,\n\t * 绝不把别的子会话的消息缓存成 A 的结果。\n\t */\n\tasync callForTask(\n\t\ttaskId: string,\n\t\trequest: Omit<Extract<SubagentTaskEnvelopeV1, { kind: \"request\" }>, \"v\" | \"kind\" | \"id\" | \"taskId\">,\n\t\trunId?: string,\n\t): Promise<SubagentTaskOkResponseEnvelopeV1> {\n\t\tconst response = await this.call({ ...request, taskId, ...(runId === undefined ? {} : { runId }) });\n\t\tif (response.taskId !== taskId) {\n\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t`runner answered task ${String(response.taskId)} for a task ${taskId} request`,\n\t\t\t\t\"cross_task_response\",\n\t\t\t);\n\t\t}\n\t\tif (runId !== undefined && response.runId !== runId) {\n\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t`runner answered run ${String(response.runId)} for a run ${runId} request`,\n\t\t\t\t\"cross_task_response\",\n\t\t\t);\n\t\t}\n\t\treturn response;\n\t}\n\n\t/** 订阅某个任务(wire taskId)的进度事件;返回退订函数。 */\n\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\tconst listeners = this.taskProgressListeners.get(taskId);\n\t\tif (listeners === undefined) this.taskProgressListeners.set(taskId, new Set([listener]));\n\t\telse listeners.add(listener);\n\t\treturn () => {\n\t\t\tconst current = this.taskProgressListeners.get(taskId);\n\t\t\tif (current === undefined) return;\n\t\t\tcurrent.delete(listener);\n\t\t\tif (current.size === 0) this.taskProgressListeners.delete(taskId);\n\t\t};\n\t}\n\n\t/** 登记 in-flight run 并接管 signal→cancel 级联;释放必须经 releaseRun。 */\n\ttrackRun(taskId: string, runId: string, signal: AbortSignal): void {\n\t\tthis.activeRuns.set(taskId, (this.activeRuns.get(taskId) ?? 0) + 1);\n\t\tthis.activeRunIds.set(taskId, runId);\n\t\t// 一次 run 至多挂一个 abort 监听;server 侧 cancel 幂等,重复触发无害。\n\t\tsignal.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tvoid this.cancelTask(taskId, abortReasonText(signal)).catch(() => {});\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t/** run 终态(resolve 或 reject)后调用:递减活跃计数并唤醒 waitForIdle。 */\n\treleaseRun(taskId: string, runId?: string): void {\n\t\tconst current = this.activeRuns.get(taskId) ?? 0;\n\t\tif (current <= 1) {\n\t\t\tthis.activeRuns.delete(taskId);\n\t\t\t// 仅释放属于该 run 的 runId 槽:并发的同名释放不会顶掉新 run 的登记。\n\t\t\tif (runId === undefined || this.activeRunIds.get(taskId) === runId) {\n\t\t\t\tthis.activeRunIds.delete(taskId);\n\t\t\t}\n\t\t\tthis.wakeIdle(taskId);\n\t\t\treturn;\n\t\t}\n\t\tthis.activeRuns.set(taskId, current - 1);\n\t}\n\n\thasActiveRun(taskId: string): boolean {\n\t\treturn (this.activeRuns.get(taskId) ?? 0) > 0;\n\t}\n\n\twaitForIdle(taskId: string): Promise<void> {\n\t\tif (!this.hasActiveRun(taskId)) return Promise.resolve();\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst waiters = this.idleWaiters.get(taskId);\n\t\t\tif (waiters === undefined) this.idleWaiters.set(taskId, [resolve]);\n\t\t\telse waiters.push(resolve);\n\t\t});\n\t}\n\n\tprivate wakeIdle(taskId: string): void {\n\t\tfor (const wake of this.idleWaiters.get(taskId)?.splice(0) ?? []) wake();\n\t}\n\n\tasync refreshMessages(taskId: string): Promise<void> {\n\t\tconst response = await this.callForTask(taskId, { op: \"result\" });\n\t\tthis.messageCache.set(taskId, response.messages ?? []);\n\t}\n\n\tcachedMessages(taskId: string): readonly unknown[] {\n\t\treturn this.messageCache.get(taskId) ?? [];\n\t}\n\n\t/**\n\t * 释放某任务的缓存:终态后消息快照与进度订阅都不再需要,长寿命 runner 连接\n\t * 不能按任务数无界增长(每条快照上限是 settle 预算)。释放顺序由调度器保证:\n\t * settle 先读 getMessages,再调用 host.dispose。\n\t */\n\tdropTask(taskId: string): void {\n\t\tthis.messageCache.delete(taskId);\n\t\tthis.taskProgressListeners.delete(taskId);\n\t\tthis.activeRunIds.delete(taskId);\n\t\tthis.appliedProfiles.delete(taskId);\n\t}\n\n\t/** 记录 runner 自报的档案事实(create 应答)。 */\n\trememberAppliedProfile(taskId: string, applied: SubagentTaskAppliedProfileV1 | undefined): void {\n\t\tif (applied === undefined) return;\n\t\tthis.appliedProfiles.set(taskId, applied);\n\t}\n\n\tappliedProfile(taskId: string): SubagentTaskAppliedProfileV1 | undefined {\n\t\treturn this.appliedProfiles.get(taskId);\n\t}\n\n\tasync cancelTask(taskId: string, reason?: string): Promise<void> {\n\t\tawait this.callForTask(taskId, { op: \"cancel\", ...(reason === undefined ? {} : { reason }) });\n\t}\n\n\t/** 父→子引导(D-060 S5 pooled parity):steer op 到 runner 叶子会话。 */\n\tasync steerTask(taskId: string, text: string): Promise<void> {\n\t\tawait this.callForTask(taskId, { op: \"steer\", text });\n\t}\n}\n\n/**\n * 远程 `AgentTaskAdapter`:与本地 SDK adapter 语义对齐——create 分配 runner 侧\n * 会话;run resolve = prompt 完成,`aborted` 终局抛 `AbortError` 类取消错误\n * (与 sdk.ts 的 aborted PromptOutcome 处理一致,由 guards 归到 cancelled,\n * 不得落成 succeeded);cancel 幂等;dispose 释放。channel 关闭或读失败时\n * 全部在途请求 reject(保留错误码),关闭后的新请求立即 reject 不悬挂。\n */\nexport function createRemoteAgentTaskAdapter(\n\tchannel: SubagentTaskChannelV1,\n): AgentTaskAdapter & SubagentTaskProgressAdapterV1 {\n\tconst client = new RemoteTaskClient(channel);\n\tconst liveTaskIds = new Set<string>();\n\treturn {\n\t\t/** D-044 §5.6:把 runner 侧的 progress 事件按 wire taskId 转给上层订阅者。 */\n\t\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\t\treturn client.onTaskProgress(taskId, listener);\n\t\t},\n\t\tcreate: async (request: AgentTaskCreateRequest): Promise<AgentTaskHost> => {\n\t\t\t// 子任务档案随 create 过线:runner 侧叶子会话按它收窄,并在应答里回实际事实。\n\t\t\tconst profile = request.metadata?.[AGENT_TASK_CHILD_PROFILE_KEY];\n\t\t\tconst parentSessionId = request.metadata?.[AGENT_TASK_PARENT_SESSION_KEY];\n\t\t\t// resume 目标(D-060 S5 pooled parity):runner 打开既有会话文件续写,不新建。\n\t\t\tconst resumeSessionId = request.metadata?.[AGENT_TASK_RESUME_SESSION_KEY];\n\t\t\t// 回合级血缘(第 3 期第二批):创建子会话的父回合 correlationId,仅 create 新建消费。\n\t\t\tconst parentTraceId = request.metadata?.[AGENT_TASK_PARENT_TRACE_KEY];\n\t\t\tconst created = await client.call({\n\t\t\t\top: \"create\",\n\t\t\t\tprompt: request.prompt,\n\t\t\t\t...(profile === undefined ? {} : { profile }),\n\t\t\t\t...(typeof parentSessionId === \"string\" ? { parentSessionId } : {}),\n\t\t\t\t...(typeof resumeSessionId === \"string\" ? { resumeSessionId } : {}),\n\t\t\t\t...(typeof parentTraceId === \"string\" ? { parentTraceId } : {}),\n\t\t\t});\n\t\t\tconst taskId = created.taskId;\n\t\t\tif (taskId === undefined) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\"create response missing taskId\", \"invalid_request\");\n\t\t\t}\n\t\t\t// 任务 id 必须唯一:runner 若把已存活任务的 id 再发一次,就是身份复用,\n\t\t\t// 之后两个任务的应答将无法区分——直接硬失败而不是继续跑。\n\t\t\tif (liveTaskIds.has(taskId)) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t\t`runner reused the id of a live task: ${taskId}`,\n\t\t\t\t\t\"cross_task_response\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tliveTaskIds.add(taskId);\n\t\t\tclient.rememberAppliedProfile(taskId, created.appliedProfile);\n\t\t\t// 叶子会话自身的 sessionId(D-060 S1):宿主可见的 getSessionId() 是 wire 任务 id,\n\t\t\t// 真正的 agent 会话 id 走 getAgentSessionId 暴露。\n\t\t\tconst agentSessionId = created.sessionId;\n\t\t\tconst host: AgentTaskHost = {\n\t\t\t\tsession: createRemoteSessionProxy(taskId, client, agentSessionId),\n\t\t\t\trun: (prompt: string, signal: AbortSignal): Promise<void> => {\n\t\t\t\t\tconst runId = `run:${randomUUID().slice(0, 8)}`;\n\t\t\t\t\tif (signal.aborted) {\n\t\t\t\t\t\t// 与本地 SDK adapter 一致:入口即中止只本地拒绝,不向 runner 发取消——\n\t\t\t\t\t\t// 什么都没有启动,任务保持可用(发取消会把任务标记为终态)。\n\t\t\t\t\t\treturn Promise.reject(abortLikeError(`run aborted before start: ${abortReasonText(signal)}`));\n\t\t\t\t\t}\n\t\t\t\t\tclient.trackRun(taskId, runId, signal);\n\t\t\t\t\treturn client\n\t\t\t\t\t\t.callForTask(taskId, { op: \"run\", prompt }, runId)\n\t\t\t\t\t\t.then(async (response) => {\n\t\t\t\t\t\t\t// run 终态后预取有界消息,供调度器 settle 同步读取。\n\t\t\t\t\t\t\t// 预取失败本身可容忍(拿不到消息不等于任务失败),但身份违规不可\n\t\t\t\t\t\t\t// 容忍:那是 runner 把别的任务的消息算到了这个任务上。\n\t\t\t\t\t\t\tawait client.refreshMessages(taskId).catch((error: unknown) => {\n\t\t\t\t\t\t\t\tif (isCrossTaskViolation(error)) throw error;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (response.status === \"cancelled\") {\n\t\t\t\t\t\t\t\tthrow abortLikeError(\"agent task run was cancelled\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\t\t// 取消先于 run 到达:runner 以 task_terminal 拒绝启动。父侧确实请求过取消,\n\t\t\t\t\t\t\t// 因此仍按取消类错误结算(与\"aborted 终局\"同一分类),不落成 failed。\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tsignal.aborted &&\n\t\t\t\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t\t\t(error as { code?: unknown }).code === \"task_terminal\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow abortLikeError(`agent task run was cancelled before start: ${abortReasonText(signal)}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.finally(() => client.releaseRun(taskId, runId));\n\t\t\t\t},\n\t\t\t\tcancel: (reason?: string): Promise<void> => client.cancelTask(taskId, reason),\n\t\t\t\tdispose: async (): Promise<void> => {\n\t\t\t\t\tliveTaskIds.delete(taskId);\n\t\t\t\t\tawait client.callForTask(taskId, { op: \"dispose\" });\n\t\t\t\t\tclient.dropTask(taskId);\n\t\t\t\t},\n\t\t\t};\n\t\t\treturn host;\n\t\t},\n\t\tdispose: async (): Promise<void> => {\n\t\t\t// 宿主会话销毁时释放全部未 dispose 的任务(逐个容错,不阻断其余回收)。\n\t\t\tfor (const taskId of [...liveTaskIds]) {\n\t\t\t\tliveTaskIds.delete(taskId);\n\t\t\t\tawait client.callForTask(taskId, { op: \"dispose\" }).catch(() => {});\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
@@ -66,6 +66,11 @@ function createRemoteSessionProxy(taskId, client, agentSessionId) {
66
66
  ...(client.appliedProfile(taskId)?.model === undefined
67
67
  ? {}
68
68
  : { getModel: () => ({ ...client.appliedProfile(taskId)?.model }) }),
69
+ // P2 parity: the runner echoes the applied web-search mode; the parent-side
70
+ // profile verification reads it through the same facts face as tools/model.
71
+ ...(client.appliedProfile(taskId)?.webSearch === undefined
72
+ ? {}
73
+ : { getWebSearch: () => client.appliedProfile(taskId)?.webSearch ?? "off" }),
69
74
  // 父→子引导(D-060 S5 pooled parity):经 wire steer op 到叶子会话自身 steer。
70
75
  steer: (text) => client.steerTask(taskId, text),
71
76
  };
@@ -1 +1 @@
1
- {"version":3,"file":"remote-adapter.js","sourceRoot":"","sources":["../src/remote-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * subagent-task 远程 adapter(D-045 / pooled 切片第 1 增量)。\n *\n * `AgentTaskAdapter` 的跨进程实现:经 `SubagentTaskChannelV1` 与 runner 侧\n * server 对话(create/run/cancel/dispose/result)。run 语义与本地一致——\n * `host.run()` resolve = 该次 prompt 完成(aborted 是正常结果);signal 中止\n * 时发 cancel 并等待 run 终态。`session.getMessages()` 为同步签名,消息在\n * run 终态时经 result op 预取缓存。本文件不做进程 spawn(runner 生命周期属\n * pooled 切片第 2 增量)。\n *\n * 迁自宿主 `src/plugins/subagent-task/remote-adapter.ts`(D-075 S4 第三批);公共契约\n * 改自 plugin-sdk,wire 协议/进度/server 事实类型改自 @agent-forge/protocol(宿主侧\n * 同名模块已下沉该包)。\n */\nimport { randomUUID } from \"node:crypto\";\nimport {\n\tAGENT_TASK_CHILD_PROFILE_KEY,\n\tAGENT_TASK_PARENT_SESSION_KEY,\n\tAGENT_TASK_PARENT_TRACE_KEY,\n\tAGENT_TASK_RESUME_SESSION_KEY,\n\ttype AgentTaskAdapter,\n\ttype AgentTaskCreateRequest,\n\ttype AgentTaskHost,\n\ttype ModelFactsViewV1,\n\ttype SessionAPI,\n} from \"@agent-forge/plugin-sdk\";\nimport {\n\tSUBAGENT_TASK_PROTOCOL_VERSION,\n\ttype SubagentTaskAppliedProfileV1,\n\ttype SubagentTaskChannelV1,\n\ttype SubagentTaskEnvelopeV1,\n\ttype SubagentTaskOkResponseEnvelopeV1,\n\ttype SubagentTaskProgressAdapterV1,\n\tSubagentTaskProtocolError,\n} from \"@agent-forge/protocol/subagent\";\n\ninterface PendingRequest {\n\tresolve(env: SubagentTaskOkResponseEnvelopeV1): void;\n\treject(error: SubagentTaskProtocolError): void;\n}\n\n/** 与本地 SDK adapter 相同的取消原因规范化:非字符串 reason 记为 \"cancelled\"。 */\nfunction abortReasonText(signal: AbortSignal): string {\n\treturn typeof signal.reason === \"string\" ? signal.reason : \"cancelled\";\n}\n\n/** 身份违规(跨任务应答):一律硬失败,绝不降级成\"拿不到结果\"。 */\nfunction isCrossTaskViolation(error: unknown): boolean {\n\treturn typeof error === \"object\" && error !== null && (error as { code?: unknown }).code === \"cross_task_response\";\n}\n\n/** 与 sdk.ts abortError 同形的取消类错误:name=\"AbortError\",由 guards 归到 cancelled。 */\nfunction abortLikeError(message: string): Error {\n\tconst error = new Error(message);\n\terror.name = \"AbortError\";\n\treturn error;\n}\n\n/**\n * 远程 host.session 只实现调度路径实际消费的面:getSessionId/getMessages\n * (run 终态时预取的有界快照)/isIdle/abort(映射为 cancel)/waitForIdle。\n * prompt 为桩——远程路径经 host.run 走 run op,不支持对 remote session 直接\n * prompt。桩边界以 docs/design/子代理pooled切片与Agent服务协议边界设计.md §4 为准。\n */\n\nfunction createRemoteSessionProxy(taskId: string, client: RemoteTaskClient, agentSessionId?: string): SessionAPI {\n\t// 远程调度路径不使用的 SessionAPI 成员:显式桩(抛协议错误),不静默返回假数据。\n\tconst unsupportedAsync = (name: string): (() => Promise<never>) => {\n\t\treturn async () => {\n\t\t\tthrow new SubagentTaskProtocolError(`remote session does not support ${name}`);\n\t\t};\n\t};\n\tconst unsupportedSync = (name: string): (() => never) => {\n\t\treturn () => {\n\t\t\tthrow new SubagentTaskProtocolError(`remote session does not support ${name}`);\n\t\t};\n\t};\n\treturn {\n\t\tgetSessionId: () => taskId,\n\t\t// 叶子会话自身身份:父侧记录与回读用它(而不是 wire 任务 id)。\n\t\t...(agentSessionId === undefined ? {} : { getAgentSessionId: () => agentSessionId }),\n\t\tgetMessages: () => client.cachedMessages(taskId),\n\t\tisIdle: () => !client.hasActiveRun(taskId),\n\t\tprompt: unsupportedAsync(\"direct prompt; use AgentTaskHost.run\"),\n\t\tabort: () => client.cancelTask(taskId, \"session abort\"),\n\t\twaitForIdle: () => client.waitForIdle(taskId),\n\t\tappendEntry: unsupportedSync(\"appendEntry\"),\n\t\tgetBranchEntries: unsupportedSync(\"getBranchEntries\"),\n\t\t// 事实面(runner 自报):档案核验需要它们。runner 未回事实时**不声明**这些成员——\n\t\t// 上层因此看到\"宿主不暴露事实\"并按无法自证处理,而不是被空数组糊弄成通过。\n\t\t...(client.appliedProfile(taskId)?.activeTools === undefined\n\t\t\t? {}\n\t\t\t: { getActiveTools: (): string[] => [...(client.appliedProfile(taskId)?.activeTools ?? [])] }),\n\t\t...(client.appliedProfile(taskId)?.model === undefined\n\t\t\t? {}\n\t\t\t: { getModel: (): ModelFactsViewV1 => ({ ...(client.appliedProfile(taskId)?.model as ModelFactsViewV1) }) }),\n\t\t// 父→子引导(D-060 S5 pooled parity):经 wire steer op 到叶子会话自身 steer。\n\t\tsteer: (text: string) => client.steerTask(taskId, text),\n\t};\n}\n\nclass RemoteTaskClient {\n\tprivate readonly channel: SubagentTaskChannelV1;\n\tprivate requestSequence = 0;\n\tprivate readonly pending = new Map<string, PendingRequest>();\n\tprivate readonly taskProgressListeners = new Map<string, Set<(message: string | undefined, seq: number) => void>>();\n\tprivate readonly activeRuns = new Map<string, number>();\n\t/** 每个任务当前 run 的 runId:进度事件按此校验,陈旧或串台 run 的进度不得投递。 */\n\tprivate readonly activeRunIds = new Map<string, string>();\n\tprivate readonly idleWaiters = new Map<string, Array<() => void>>();\n\tprivate readonly messageCache = new Map<string, readonly unknown[]>();\n\t/** create 应答里 runner 自报的收窄事实(工具面/模型/模式):代理据此暴露可核验面。 */\n\tprivate readonly appliedProfiles = new Map<string, SubagentTaskAppliedProfileV1>();\n\tprivate reader: Promise<void> | undefined;\n\tprivate closed = false;\n\n\tconstructor(channel: SubagentTaskChannelV1) {\n\t\tthis.channel = channel;\n\t}\n\n\tstart(): void {\n\t\tif (this.reader !== undefined) return;\n\t\tthis.reader = (async () => {\n\t\t\ttry {\n\t\t\t\tfor await (const env of this.channel) {\n\t\t\t\t\tthis.dispatch(env);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.failAllPending(error instanceof Error ? error : new SubagentTaskProtocolError(\"channel read failed\"));\n\t\t\t}\n\t\t\t// 通道关闭 = 对端(runner 进程)已消失:在途任务按 runner_lost 结算,\n\t\t\t// 由调度器投影为 failed + reasonCode subagent_runner_lost(D-044 §4.3)。\n\t\t\tthis.failAllPending(new SubagentTaskProtocolError(\"subagent runner lost: channel closed\", \"runner_lost\"));\n\t\t})();\n\t\tvoid this.reader.catch(() => {});\n\t}\n\n\tprivate dispatch(env: SubagentTaskEnvelopeV1): void {\n\t\tif (env.kind === \"response\") {\n\t\t\tconst pending = this.pending.get(env.id);\n\t\t\tif (pending === undefined) return; // 未知响应:丢弃(迟到回执)\n\t\t\tthis.pending.delete(env.id);\n\t\t\tif (env.ok) pending.resolve(env);\n\t\t\telse pending.reject(new SubagentTaskProtocolError(env.message, env.code));\n\t\t\treturn;\n\t\t}\n\t\tif (env.kind === \"event\") {\n\t\t\t// 隔离校验:只有\"该任务当前 run\"的进度才投递。runner 侧陈旧批次、\n\t\t\t// 或身份错标(B 任务的进度挂在 A 的 taskId 上)一律丢弃,宁可少一条\n\t\t\t// 提示也不让父侧把别的子会话的进度算到当前任务上。\n\t\t\tconst expectedRunId = this.activeRunIds.get(env.taskId);\n\t\t\tif (expectedRunId === undefined || env.runId !== expectedRunId) return;\n\t\t\tconst taskListeners = this.taskProgressListeners.get(env.taskId);\n\t\t\tif (taskListeners !== undefined) {\n\t\t\t\tfor (const listener of taskListeners) listener(env.message, env.seq);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate failAllPending(error: SubagentTaskProtocolError): void {\n\t\tthis.closed = true;\n\t\tfor (const pending of this.pending.values()) pending.reject(error);\n\t\tthis.pending.clear();\n\t}\n\n\tcall(\n\t\trequest: Omit<Extract<SubagentTaskEnvelopeV1, { kind: \"request\" }>, \"v\" | \"kind\" | \"id\">,\n\t): Promise<SubagentTaskOkResponseEnvelopeV1> {\n\t\t// 通道已关闭后不再入队:立即 reject,避免调用方永久悬挂。\n\t\tif (this.closed) {\n\t\t\treturn Promise.reject(new SubagentTaskProtocolError(\"subagent runner lost: channel closed\", \"runner_lost\"));\n\t\t}\n\t\tthis.start();\n\t\tconst id = `req:${++this.requestSequence}:${randomUUID().slice(0, 8)}`;\n\t\treturn new Promise<SubagentTaskOkResponseEnvelopeV1>((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve, reject });\n\t\t\tvoid this.channel.write({ v: SUBAGENT_TASK_PROTOCOL_VERSION, kind: \"request\", id, ...request });\n\t\t});\n\t}\n\n\t/**\n\t * 任务作用域调用:请求与应答必须是同一个任务。runner 若就 A 的请求回 B 的\n\t * taskId/runId(身份错标、状态错位),这里按 `cross_task_response` 硬失败,\n\t * 绝不把别的子会话的消息缓存成 A 的结果。\n\t */\n\tasync callForTask(\n\t\ttaskId: string,\n\t\trequest: Omit<Extract<SubagentTaskEnvelopeV1, { kind: \"request\" }>, \"v\" | \"kind\" | \"id\" | \"taskId\">,\n\t\trunId?: string,\n\t): Promise<SubagentTaskOkResponseEnvelopeV1> {\n\t\tconst response = await this.call({ ...request, taskId, ...(runId === undefined ? {} : { runId }) });\n\t\tif (response.taskId !== taskId) {\n\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t`runner answered task ${String(response.taskId)} for a task ${taskId} request`,\n\t\t\t\t\"cross_task_response\",\n\t\t\t);\n\t\t}\n\t\tif (runId !== undefined && response.runId !== runId) {\n\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t`runner answered run ${String(response.runId)} for a run ${runId} request`,\n\t\t\t\t\"cross_task_response\",\n\t\t\t);\n\t\t}\n\t\treturn response;\n\t}\n\n\t/** 订阅某个任务(wire taskId)的进度事件;返回退订函数。 */\n\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\tconst listeners = this.taskProgressListeners.get(taskId);\n\t\tif (listeners === undefined) this.taskProgressListeners.set(taskId, new Set([listener]));\n\t\telse listeners.add(listener);\n\t\treturn () => {\n\t\t\tconst current = this.taskProgressListeners.get(taskId);\n\t\t\tif (current === undefined) return;\n\t\t\tcurrent.delete(listener);\n\t\t\tif (current.size === 0) this.taskProgressListeners.delete(taskId);\n\t\t};\n\t}\n\n\t/** 登记 in-flight run 并接管 signal→cancel 级联;释放必须经 releaseRun。 */\n\ttrackRun(taskId: string, runId: string, signal: AbortSignal): void {\n\t\tthis.activeRuns.set(taskId, (this.activeRuns.get(taskId) ?? 0) + 1);\n\t\tthis.activeRunIds.set(taskId, runId);\n\t\t// 一次 run 至多挂一个 abort 监听;server 侧 cancel 幂等,重复触发无害。\n\t\tsignal.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tvoid this.cancelTask(taskId, abortReasonText(signal)).catch(() => {});\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t/** run 终态(resolve 或 reject)后调用:递减活跃计数并唤醒 waitForIdle。 */\n\treleaseRun(taskId: string, runId?: string): void {\n\t\tconst current = this.activeRuns.get(taskId) ?? 0;\n\t\tif (current <= 1) {\n\t\t\tthis.activeRuns.delete(taskId);\n\t\t\t// 仅释放属于该 run 的 runId 槽:并发的同名释放不会顶掉新 run 的登记。\n\t\t\tif (runId === undefined || this.activeRunIds.get(taskId) === runId) {\n\t\t\t\tthis.activeRunIds.delete(taskId);\n\t\t\t}\n\t\t\tthis.wakeIdle(taskId);\n\t\t\treturn;\n\t\t}\n\t\tthis.activeRuns.set(taskId, current - 1);\n\t}\n\n\thasActiveRun(taskId: string): boolean {\n\t\treturn (this.activeRuns.get(taskId) ?? 0) > 0;\n\t}\n\n\twaitForIdle(taskId: string): Promise<void> {\n\t\tif (!this.hasActiveRun(taskId)) return Promise.resolve();\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst waiters = this.idleWaiters.get(taskId);\n\t\t\tif (waiters === undefined) this.idleWaiters.set(taskId, [resolve]);\n\t\t\telse waiters.push(resolve);\n\t\t});\n\t}\n\n\tprivate wakeIdle(taskId: string): void {\n\t\tfor (const wake of this.idleWaiters.get(taskId)?.splice(0) ?? []) wake();\n\t}\n\n\tasync refreshMessages(taskId: string): Promise<void> {\n\t\tconst response = await this.callForTask(taskId, { op: \"result\" });\n\t\tthis.messageCache.set(taskId, response.messages ?? []);\n\t}\n\n\tcachedMessages(taskId: string): readonly unknown[] {\n\t\treturn this.messageCache.get(taskId) ?? [];\n\t}\n\n\t/**\n\t * 释放某任务的缓存:终态后消息快照与进度订阅都不再需要,长寿命 runner 连接\n\t * 不能按任务数无界增长(每条快照上限是 settle 预算)。释放顺序由调度器保证:\n\t * settle 先读 getMessages,再调用 host.dispose。\n\t */\n\tdropTask(taskId: string): void {\n\t\tthis.messageCache.delete(taskId);\n\t\tthis.taskProgressListeners.delete(taskId);\n\t\tthis.activeRunIds.delete(taskId);\n\t\tthis.appliedProfiles.delete(taskId);\n\t}\n\n\t/** 记录 runner 自报的档案事实(create 应答)。 */\n\trememberAppliedProfile(taskId: string, applied: SubagentTaskAppliedProfileV1 | undefined): void {\n\t\tif (applied === undefined) return;\n\t\tthis.appliedProfiles.set(taskId, applied);\n\t}\n\n\tappliedProfile(taskId: string): SubagentTaskAppliedProfileV1 | undefined {\n\t\treturn this.appliedProfiles.get(taskId);\n\t}\n\n\tasync cancelTask(taskId: string, reason?: string): Promise<void> {\n\t\tawait this.callForTask(taskId, { op: \"cancel\", ...(reason === undefined ? {} : { reason }) });\n\t}\n\n\t/** 父→子引导(D-060 S5 pooled parity):steer op 到 runner 叶子会话。 */\n\tasync steerTask(taskId: string, text: string): Promise<void> {\n\t\tawait this.callForTask(taskId, { op: \"steer\", text });\n\t}\n}\n\n/**\n * 远程 `AgentTaskAdapter`:与本地 SDK adapter 语义对齐——create 分配 runner 侧\n * 会话;run resolve = prompt 完成,`aborted` 终局抛 `AbortError` 类取消错误\n * (与 sdk.ts 的 aborted PromptOutcome 处理一致,由 guards 归到 cancelled,\n * 不得落成 succeeded);cancel 幂等;dispose 释放。channel 关闭或读失败时\n * 全部在途请求 reject(保留错误码),关闭后的新请求立即 reject 不悬挂。\n */\nexport function createRemoteAgentTaskAdapter(\n\tchannel: SubagentTaskChannelV1,\n): AgentTaskAdapter & SubagentTaskProgressAdapterV1 {\n\tconst client = new RemoteTaskClient(channel);\n\tconst liveTaskIds = new Set<string>();\n\treturn {\n\t\t/** D-044 §5.6:把 runner 侧的 progress 事件按 wire taskId 转给上层订阅者。 */\n\t\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\t\treturn client.onTaskProgress(taskId, listener);\n\t\t},\n\t\tcreate: async (request: AgentTaskCreateRequest): Promise<AgentTaskHost> => {\n\t\t\t// 子任务档案随 create 过线:runner 侧叶子会话按它收窄,并在应答里回实际事实。\n\t\t\tconst profile = request.metadata?.[AGENT_TASK_CHILD_PROFILE_KEY];\n\t\t\tconst parentSessionId = request.metadata?.[AGENT_TASK_PARENT_SESSION_KEY];\n\t\t\t// resume 目标(D-060 S5 pooled parity):runner 打开既有会话文件续写,不新建。\n\t\t\tconst resumeSessionId = request.metadata?.[AGENT_TASK_RESUME_SESSION_KEY];\n\t\t\t// 回合级血缘(第 3 期第二批):创建子会话的父回合 correlationId,仅 create 新建消费。\n\t\t\tconst parentTraceId = request.metadata?.[AGENT_TASK_PARENT_TRACE_KEY];\n\t\t\tconst created = await client.call({\n\t\t\t\top: \"create\",\n\t\t\t\tprompt: request.prompt,\n\t\t\t\t...(profile === undefined ? {} : { profile }),\n\t\t\t\t...(typeof parentSessionId === \"string\" ? { parentSessionId } : {}),\n\t\t\t\t...(typeof resumeSessionId === \"string\" ? { resumeSessionId } : {}),\n\t\t\t\t...(typeof parentTraceId === \"string\" ? { parentTraceId } : {}),\n\t\t\t});\n\t\t\tconst taskId = created.taskId;\n\t\t\tif (taskId === undefined) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\"create response missing taskId\", \"invalid_request\");\n\t\t\t}\n\t\t\t// 任务 id 必须唯一:runner 若把已存活任务的 id 再发一次,就是身份复用,\n\t\t\t// 之后两个任务的应答将无法区分——直接硬失败而不是继续跑。\n\t\t\tif (liveTaskIds.has(taskId)) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t\t`runner reused the id of a live task: ${taskId}`,\n\t\t\t\t\t\"cross_task_response\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tliveTaskIds.add(taskId);\n\t\t\tclient.rememberAppliedProfile(taskId, created.appliedProfile);\n\t\t\t// 叶子会话自身的 sessionId(D-060 S1):宿主可见的 getSessionId() 是 wire 任务 id,\n\t\t\t// 真正的 agent 会话 id 走 getAgentSessionId 暴露。\n\t\t\tconst agentSessionId = created.sessionId;\n\t\t\tconst host: AgentTaskHost = {\n\t\t\t\tsession: createRemoteSessionProxy(taskId, client, agentSessionId),\n\t\t\t\trun: (prompt: string, signal: AbortSignal): Promise<void> => {\n\t\t\t\t\tconst runId = `run:${randomUUID().slice(0, 8)}`;\n\t\t\t\t\tif (signal.aborted) {\n\t\t\t\t\t\t// 与本地 SDK adapter 一致:入口即中止只本地拒绝,不向 runner 发取消——\n\t\t\t\t\t\t// 什么都没有启动,任务保持可用(发取消会把任务标记为终态)。\n\t\t\t\t\t\treturn Promise.reject(abortLikeError(`run aborted before start: ${abortReasonText(signal)}`));\n\t\t\t\t\t}\n\t\t\t\t\tclient.trackRun(taskId, runId, signal);\n\t\t\t\t\treturn client\n\t\t\t\t\t\t.callForTask(taskId, { op: \"run\", prompt }, runId)\n\t\t\t\t\t\t.then(async (response) => {\n\t\t\t\t\t\t\t// run 终态后预取有界消息,供调度器 settle 同步读取。\n\t\t\t\t\t\t\t// 预取失败本身可容忍(拿不到消息不等于任务失败),但身份违规不可\n\t\t\t\t\t\t\t// 容忍:那是 runner 把别的任务的消息算到了这个任务上。\n\t\t\t\t\t\t\tawait client.refreshMessages(taskId).catch((error: unknown) => {\n\t\t\t\t\t\t\t\tif (isCrossTaskViolation(error)) throw error;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (response.status === \"cancelled\") {\n\t\t\t\t\t\t\t\tthrow abortLikeError(\"agent task run was cancelled\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\t\t// 取消先于 run 到达:runner 以 task_terminal 拒绝启动。父侧确实请求过取消,\n\t\t\t\t\t\t\t// 因此仍按取消类错误结算(与\"aborted 终局\"同一分类),不落成 failed。\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tsignal.aborted &&\n\t\t\t\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t\t\t(error as { code?: unknown }).code === \"task_terminal\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow abortLikeError(`agent task run was cancelled before start: ${abortReasonText(signal)}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.finally(() => client.releaseRun(taskId, runId));\n\t\t\t\t},\n\t\t\t\tcancel: (reason?: string): Promise<void> => client.cancelTask(taskId, reason),\n\t\t\t\tdispose: async (): Promise<void> => {\n\t\t\t\t\tliveTaskIds.delete(taskId);\n\t\t\t\t\tawait client.callForTask(taskId, { op: \"dispose\" });\n\t\t\t\t\tclient.dropTask(taskId);\n\t\t\t\t},\n\t\t\t};\n\t\t\treturn host;\n\t\t},\n\t\tdispose: async (): Promise<void> => {\n\t\t\t// 宿主会话销毁时释放全部未 dispose 的任务(逐个容错,不阻断其余回收)。\n\t\t\tfor (const taskId of [...liveTaskIds]) {\n\t\t\t\tliveTaskIds.delete(taskId);\n\t\t\t\tawait client.callForTask(taskId, { op: \"dispose\" }).catch(() => {});\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"remote-adapter.js","sourceRoot":"","sources":["../src/remote-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * subagent-task 远程 adapter(D-045 / pooled 切片第 1 增量)。\n *\n * `AgentTaskAdapter` 的跨进程实现:经 `SubagentTaskChannelV1` 与 runner 侧\n * server 对话(create/run/cancel/dispose/result)。run 语义与本地一致——\n * `host.run()` resolve = 该次 prompt 完成(aborted 是正常结果);signal 中止\n * 时发 cancel 并等待 run 终态。`session.getMessages()` 为同步签名,消息在\n * run 终态时经 result op 预取缓存。本文件不做进程 spawn(runner 生命周期属\n * pooled 切片第 2 增量)。\n *\n * 迁自宿主 `src/plugins/subagent-task/remote-adapter.ts`(D-075 S4 第三批);公共契约\n * 改自 plugin-sdk,wire 协议/进度/server 事实类型改自 @agent-forge/protocol(宿主侧\n * 同名模块已下沉该包)。\n */\nimport { randomUUID } from \"node:crypto\";\nimport {\n\tAGENT_TASK_CHILD_PROFILE_KEY,\n\tAGENT_TASK_PARENT_SESSION_KEY,\n\tAGENT_TASK_PARENT_TRACE_KEY,\n\tAGENT_TASK_RESUME_SESSION_KEY,\n\ttype AgentTaskAdapter,\n\ttype AgentTaskCreateRequest,\n\ttype AgentTaskHost,\n\ttype ModelFactsViewV1,\n\ttype SessionAPI,\n} from \"@agent-forge/plugin-sdk\";\nimport {\n\tSUBAGENT_TASK_PROTOCOL_VERSION,\n\ttype SubagentTaskAppliedProfileV1,\n\ttype SubagentTaskChannelV1,\n\ttype SubagentTaskEnvelopeV1,\n\ttype SubagentTaskOkResponseEnvelopeV1,\n\ttype SubagentTaskProgressAdapterV1,\n\tSubagentTaskProtocolError,\n} from \"@agent-forge/protocol/subagent\";\n\ninterface PendingRequest {\n\tresolve(env: SubagentTaskOkResponseEnvelopeV1): void;\n\treject(error: SubagentTaskProtocolError): void;\n}\n\n/** 与本地 SDK adapter 相同的取消原因规范化:非字符串 reason 记为 \"cancelled\"。 */\nfunction abortReasonText(signal: AbortSignal): string {\n\treturn typeof signal.reason === \"string\" ? signal.reason : \"cancelled\";\n}\n\n/** 身份违规(跨任务应答):一律硬失败,绝不降级成\"拿不到结果\"。 */\nfunction isCrossTaskViolation(error: unknown): boolean {\n\treturn typeof error === \"object\" && error !== null && (error as { code?: unknown }).code === \"cross_task_response\";\n}\n\n/** 与 sdk.ts abortError 同形的取消类错误:name=\"AbortError\",由 guards 归到 cancelled。 */\nfunction abortLikeError(message: string): Error {\n\tconst error = new Error(message);\n\terror.name = \"AbortError\";\n\treturn error;\n}\n\n/**\n * 远程 host.session 只实现调度路径实际消费的面:getSessionId/getMessages\n * (run 终态时预取的有界快照)/isIdle/abort(映射为 cancel)/waitForIdle。\n * prompt 为桩——远程路径经 host.run 走 run op,不支持对 remote session 直接\n * prompt。桩边界以 docs/design/子代理pooled切片与Agent服务协议边界设计.md §4 为准。\n */\n\nfunction createRemoteSessionProxy(taskId: string, client: RemoteTaskClient, agentSessionId?: string): SessionAPI {\n\t// 远程调度路径不使用的 SessionAPI 成员:显式桩(抛协议错误),不静默返回假数据。\n\tconst unsupportedAsync = (name: string): (() => Promise<never>) => {\n\t\treturn async () => {\n\t\t\tthrow new SubagentTaskProtocolError(`remote session does not support ${name}`);\n\t\t};\n\t};\n\tconst unsupportedSync = (name: string): (() => never) => {\n\t\treturn () => {\n\t\t\tthrow new SubagentTaskProtocolError(`remote session does not support ${name}`);\n\t\t};\n\t};\n\treturn {\n\t\tgetSessionId: () => taskId,\n\t\t// 叶子会话自身身份:父侧记录与回读用它(而不是 wire 任务 id)。\n\t\t...(agentSessionId === undefined ? {} : { getAgentSessionId: () => agentSessionId }),\n\t\tgetMessages: () => client.cachedMessages(taskId),\n\t\tisIdle: () => !client.hasActiveRun(taskId),\n\t\tprompt: unsupportedAsync(\"direct prompt; use AgentTaskHost.run\"),\n\t\tabort: () => client.cancelTask(taskId, \"session abort\"),\n\t\twaitForIdle: () => client.waitForIdle(taskId),\n\t\tappendEntry: unsupportedSync(\"appendEntry\"),\n\t\tgetBranchEntries: unsupportedSync(\"getBranchEntries\"),\n\t\t// 事实面(runner 自报):档案核验需要它们。runner 未回事实时**不声明**这些成员——\n\t\t// 上层因此看到\"宿主不暴露事实\"并按无法自证处理,而不是被空数组糊弄成通过。\n\t\t...(client.appliedProfile(taskId)?.activeTools === undefined\n\t\t\t? {}\n\t\t\t: { getActiveTools: (): string[] => [...(client.appliedProfile(taskId)?.activeTools ?? [])] }),\n\t\t...(client.appliedProfile(taskId)?.model === undefined\n\t\t\t? {}\n\t\t\t: { getModel: (): ModelFactsViewV1 => ({ ...(client.appliedProfile(taskId)?.model as ModelFactsViewV1) }) }),\n\t\t// P2 parity: the runner echoes the applied web-search mode; the parent-side\n\t\t// profile verification reads it through the same facts face as tools/model.\n\t\t...(client.appliedProfile(taskId)?.webSearch === undefined\n\t\t\t? {}\n\t\t\t: { getWebSearch: (): \"off\" | \"auto\" => client.appliedProfile(taskId)?.webSearch ?? \"off\" }),\n\t\t// 父→子引导(D-060 S5 pooled parity):经 wire steer op 到叶子会话自身 steer。\n\t\tsteer: (text: string) => client.steerTask(taskId, text),\n\t};\n}\n\nclass RemoteTaskClient {\n\tprivate readonly channel: SubagentTaskChannelV1;\n\tprivate requestSequence = 0;\n\tprivate readonly pending = new Map<string, PendingRequest>();\n\tprivate readonly taskProgressListeners = new Map<string, Set<(message: string | undefined, seq: number) => void>>();\n\tprivate readonly activeRuns = new Map<string, number>();\n\t/** 每个任务当前 run 的 runId:进度事件按此校验,陈旧或串台 run 的进度不得投递。 */\n\tprivate readonly activeRunIds = new Map<string, string>();\n\tprivate readonly idleWaiters = new Map<string, Array<() => void>>();\n\tprivate readonly messageCache = new Map<string, readonly unknown[]>();\n\t/** create 应答里 runner 自报的收窄事实(工具面/模型/模式):代理据此暴露可核验面。 */\n\tprivate readonly appliedProfiles = new Map<string, SubagentTaskAppliedProfileV1>();\n\tprivate reader: Promise<void> | undefined;\n\tprivate closed = false;\n\n\tconstructor(channel: SubagentTaskChannelV1) {\n\t\tthis.channel = channel;\n\t}\n\n\tstart(): void {\n\t\tif (this.reader !== undefined) return;\n\t\tthis.reader = (async () => {\n\t\t\ttry {\n\t\t\t\tfor await (const env of this.channel) {\n\t\t\t\t\tthis.dispatch(env);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.failAllPending(error instanceof Error ? error : new SubagentTaskProtocolError(\"channel read failed\"));\n\t\t\t}\n\t\t\t// 通道关闭 = 对端(runner 进程)已消失:在途任务按 runner_lost 结算,\n\t\t\t// 由调度器投影为 failed + reasonCode subagent_runner_lost(D-044 §4.3)。\n\t\t\tthis.failAllPending(new SubagentTaskProtocolError(\"subagent runner lost: channel closed\", \"runner_lost\"));\n\t\t})();\n\t\tvoid this.reader.catch(() => {});\n\t}\n\n\tprivate dispatch(env: SubagentTaskEnvelopeV1): void {\n\t\tif (env.kind === \"response\") {\n\t\t\tconst pending = this.pending.get(env.id);\n\t\t\tif (pending === undefined) return; // 未知响应:丢弃(迟到回执)\n\t\t\tthis.pending.delete(env.id);\n\t\t\tif (env.ok) pending.resolve(env);\n\t\t\telse pending.reject(new SubagentTaskProtocolError(env.message, env.code));\n\t\t\treturn;\n\t\t}\n\t\tif (env.kind === \"event\") {\n\t\t\t// 隔离校验:只有\"该任务当前 run\"的进度才投递。runner 侧陈旧批次、\n\t\t\t// 或身份错标(B 任务的进度挂在 A 的 taskId 上)一律丢弃,宁可少一条\n\t\t\t// 提示也不让父侧把别的子会话的进度算到当前任务上。\n\t\t\tconst expectedRunId = this.activeRunIds.get(env.taskId);\n\t\t\tif (expectedRunId === undefined || env.runId !== expectedRunId) return;\n\t\t\tconst taskListeners = this.taskProgressListeners.get(env.taskId);\n\t\t\tif (taskListeners !== undefined) {\n\t\t\t\tfor (const listener of taskListeners) listener(env.message, env.seq);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate failAllPending(error: SubagentTaskProtocolError): void {\n\t\tthis.closed = true;\n\t\tfor (const pending of this.pending.values()) pending.reject(error);\n\t\tthis.pending.clear();\n\t}\n\n\tcall(\n\t\trequest: Omit<Extract<SubagentTaskEnvelopeV1, { kind: \"request\" }>, \"v\" | \"kind\" | \"id\">,\n\t): Promise<SubagentTaskOkResponseEnvelopeV1> {\n\t\t// 通道已关闭后不再入队:立即 reject,避免调用方永久悬挂。\n\t\tif (this.closed) {\n\t\t\treturn Promise.reject(new SubagentTaskProtocolError(\"subagent runner lost: channel closed\", \"runner_lost\"));\n\t\t}\n\t\tthis.start();\n\t\tconst id = `req:${++this.requestSequence}:${randomUUID().slice(0, 8)}`;\n\t\treturn new Promise<SubagentTaskOkResponseEnvelopeV1>((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve, reject });\n\t\t\tvoid this.channel.write({ v: SUBAGENT_TASK_PROTOCOL_VERSION, kind: \"request\", id, ...request });\n\t\t});\n\t}\n\n\t/**\n\t * 任务作用域调用:请求与应答必须是同一个任务。runner 若就 A 的请求回 B 的\n\t * taskId/runId(身份错标、状态错位),这里按 `cross_task_response` 硬失败,\n\t * 绝不把别的子会话的消息缓存成 A 的结果。\n\t */\n\tasync callForTask(\n\t\ttaskId: string,\n\t\trequest: Omit<Extract<SubagentTaskEnvelopeV1, { kind: \"request\" }>, \"v\" | \"kind\" | \"id\" | \"taskId\">,\n\t\trunId?: string,\n\t): Promise<SubagentTaskOkResponseEnvelopeV1> {\n\t\tconst response = await this.call({ ...request, taskId, ...(runId === undefined ? {} : { runId }) });\n\t\tif (response.taskId !== taskId) {\n\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t`runner answered task ${String(response.taskId)} for a task ${taskId} request`,\n\t\t\t\t\"cross_task_response\",\n\t\t\t);\n\t\t}\n\t\tif (runId !== undefined && response.runId !== runId) {\n\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t`runner answered run ${String(response.runId)} for a run ${runId} request`,\n\t\t\t\t\"cross_task_response\",\n\t\t\t);\n\t\t}\n\t\treturn response;\n\t}\n\n\t/** 订阅某个任务(wire taskId)的进度事件;返回退订函数。 */\n\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\tconst listeners = this.taskProgressListeners.get(taskId);\n\t\tif (listeners === undefined) this.taskProgressListeners.set(taskId, new Set([listener]));\n\t\telse listeners.add(listener);\n\t\treturn () => {\n\t\t\tconst current = this.taskProgressListeners.get(taskId);\n\t\t\tif (current === undefined) return;\n\t\t\tcurrent.delete(listener);\n\t\t\tif (current.size === 0) this.taskProgressListeners.delete(taskId);\n\t\t};\n\t}\n\n\t/** 登记 in-flight run 并接管 signal→cancel 级联;释放必须经 releaseRun。 */\n\ttrackRun(taskId: string, runId: string, signal: AbortSignal): void {\n\t\tthis.activeRuns.set(taskId, (this.activeRuns.get(taskId) ?? 0) + 1);\n\t\tthis.activeRunIds.set(taskId, runId);\n\t\t// 一次 run 至多挂一个 abort 监听;server 侧 cancel 幂等,重复触发无害。\n\t\tsignal.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tvoid this.cancelTask(taskId, abortReasonText(signal)).catch(() => {});\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t/** run 终态(resolve 或 reject)后调用:递减活跃计数并唤醒 waitForIdle。 */\n\treleaseRun(taskId: string, runId?: string): void {\n\t\tconst current = this.activeRuns.get(taskId) ?? 0;\n\t\tif (current <= 1) {\n\t\t\tthis.activeRuns.delete(taskId);\n\t\t\t// 仅释放属于该 run 的 runId 槽:并发的同名释放不会顶掉新 run 的登记。\n\t\t\tif (runId === undefined || this.activeRunIds.get(taskId) === runId) {\n\t\t\t\tthis.activeRunIds.delete(taskId);\n\t\t\t}\n\t\t\tthis.wakeIdle(taskId);\n\t\t\treturn;\n\t\t}\n\t\tthis.activeRuns.set(taskId, current - 1);\n\t}\n\n\thasActiveRun(taskId: string): boolean {\n\t\treturn (this.activeRuns.get(taskId) ?? 0) > 0;\n\t}\n\n\twaitForIdle(taskId: string): Promise<void> {\n\t\tif (!this.hasActiveRun(taskId)) return Promise.resolve();\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tconst waiters = this.idleWaiters.get(taskId);\n\t\t\tif (waiters === undefined) this.idleWaiters.set(taskId, [resolve]);\n\t\t\telse waiters.push(resolve);\n\t\t});\n\t}\n\n\tprivate wakeIdle(taskId: string): void {\n\t\tfor (const wake of this.idleWaiters.get(taskId)?.splice(0) ?? []) wake();\n\t}\n\n\tasync refreshMessages(taskId: string): Promise<void> {\n\t\tconst response = await this.callForTask(taskId, { op: \"result\" });\n\t\tthis.messageCache.set(taskId, response.messages ?? []);\n\t}\n\n\tcachedMessages(taskId: string): readonly unknown[] {\n\t\treturn this.messageCache.get(taskId) ?? [];\n\t}\n\n\t/**\n\t * 释放某任务的缓存:终态后消息快照与进度订阅都不再需要,长寿命 runner 连接\n\t * 不能按任务数无界增长(每条快照上限是 settle 预算)。释放顺序由调度器保证:\n\t * settle 先读 getMessages,再调用 host.dispose。\n\t */\n\tdropTask(taskId: string): void {\n\t\tthis.messageCache.delete(taskId);\n\t\tthis.taskProgressListeners.delete(taskId);\n\t\tthis.activeRunIds.delete(taskId);\n\t\tthis.appliedProfiles.delete(taskId);\n\t}\n\n\t/** 记录 runner 自报的档案事实(create 应答)。 */\n\trememberAppliedProfile(taskId: string, applied: SubagentTaskAppliedProfileV1 | undefined): void {\n\t\tif (applied === undefined) return;\n\t\tthis.appliedProfiles.set(taskId, applied);\n\t}\n\n\tappliedProfile(taskId: string): SubagentTaskAppliedProfileV1 | undefined {\n\t\treturn this.appliedProfiles.get(taskId);\n\t}\n\n\tasync cancelTask(taskId: string, reason?: string): Promise<void> {\n\t\tawait this.callForTask(taskId, { op: \"cancel\", ...(reason === undefined ? {} : { reason }) });\n\t}\n\n\t/** 父→子引导(D-060 S5 pooled parity):steer op 到 runner 叶子会话。 */\n\tasync steerTask(taskId: string, text: string): Promise<void> {\n\t\tawait this.callForTask(taskId, { op: \"steer\", text });\n\t}\n}\n\n/**\n * 远程 `AgentTaskAdapter`:与本地 SDK adapter 语义对齐——create 分配 runner 侧\n * 会话;run resolve = prompt 完成,`aborted` 终局抛 `AbortError` 类取消错误\n * (与 sdk.ts 的 aborted PromptOutcome 处理一致,由 guards 归到 cancelled,\n * 不得落成 succeeded);cancel 幂等;dispose 释放。channel 关闭或读失败时\n * 全部在途请求 reject(保留错误码),关闭后的新请求立即 reject 不悬挂。\n */\nexport function createRemoteAgentTaskAdapter(\n\tchannel: SubagentTaskChannelV1,\n): AgentTaskAdapter & SubagentTaskProgressAdapterV1 {\n\tconst client = new RemoteTaskClient(channel);\n\tconst liveTaskIds = new Set<string>();\n\treturn {\n\t\t/** D-044 §5.6:把 runner 侧的 progress 事件按 wire taskId 转给上层订阅者。 */\n\t\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\t\treturn client.onTaskProgress(taskId, listener);\n\t\t},\n\t\tcreate: async (request: AgentTaskCreateRequest): Promise<AgentTaskHost> => {\n\t\t\t// 子任务档案随 create 过线:runner 侧叶子会话按它收窄,并在应答里回实际事实。\n\t\t\tconst profile = request.metadata?.[AGENT_TASK_CHILD_PROFILE_KEY];\n\t\t\tconst parentSessionId = request.metadata?.[AGENT_TASK_PARENT_SESSION_KEY];\n\t\t\t// resume 目标(D-060 S5 pooled parity):runner 打开既有会话文件续写,不新建。\n\t\t\tconst resumeSessionId = request.metadata?.[AGENT_TASK_RESUME_SESSION_KEY];\n\t\t\t// 回合级血缘(第 3 期第二批):创建子会话的父回合 correlationId,仅 create 新建消费。\n\t\t\tconst parentTraceId = request.metadata?.[AGENT_TASK_PARENT_TRACE_KEY];\n\t\t\tconst created = await client.call({\n\t\t\t\top: \"create\",\n\t\t\t\tprompt: request.prompt,\n\t\t\t\t...(profile === undefined ? {} : { profile }),\n\t\t\t\t...(typeof parentSessionId === \"string\" ? { parentSessionId } : {}),\n\t\t\t\t...(typeof resumeSessionId === \"string\" ? { resumeSessionId } : {}),\n\t\t\t\t...(typeof parentTraceId === \"string\" ? { parentTraceId } : {}),\n\t\t\t});\n\t\t\tconst taskId = created.taskId;\n\t\t\tif (taskId === undefined) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\"create response missing taskId\", \"invalid_request\");\n\t\t\t}\n\t\t\t// 任务 id 必须唯一:runner 若把已存活任务的 id 再发一次,就是身份复用,\n\t\t\t// 之后两个任务的应答将无法区分——直接硬失败而不是继续跑。\n\t\t\tif (liveTaskIds.has(taskId)) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t\t`runner reused the id of a live task: ${taskId}`,\n\t\t\t\t\t\"cross_task_response\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tliveTaskIds.add(taskId);\n\t\t\tclient.rememberAppliedProfile(taskId, created.appliedProfile);\n\t\t\t// 叶子会话自身的 sessionId(D-060 S1):宿主可见的 getSessionId() 是 wire 任务 id,\n\t\t\t// 真正的 agent 会话 id 走 getAgentSessionId 暴露。\n\t\t\tconst agentSessionId = created.sessionId;\n\t\t\tconst host: AgentTaskHost = {\n\t\t\t\tsession: createRemoteSessionProxy(taskId, client, agentSessionId),\n\t\t\t\trun: (prompt: string, signal: AbortSignal): Promise<void> => {\n\t\t\t\t\tconst runId = `run:${randomUUID().slice(0, 8)}`;\n\t\t\t\t\tif (signal.aborted) {\n\t\t\t\t\t\t// 与本地 SDK adapter 一致:入口即中止只本地拒绝,不向 runner 发取消——\n\t\t\t\t\t\t// 什么都没有启动,任务保持可用(发取消会把任务标记为终态)。\n\t\t\t\t\t\treturn Promise.reject(abortLikeError(`run aborted before start: ${abortReasonText(signal)}`));\n\t\t\t\t\t}\n\t\t\t\t\tclient.trackRun(taskId, runId, signal);\n\t\t\t\t\treturn client\n\t\t\t\t\t\t.callForTask(taskId, { op: \"run\", prompt }, runId)\n\t\t\t\t\t\t.then(async (response) => {\n\t\t\t\t\t\t\t// run 终态后预取有界消息,供调度器 settle 同步读取。\n\t\t\t\t\t\t\t// 预取失败本身可容忍(拿不到消息不等于任务失败),但身份违规不可\n\t\t\t\t\t\t\t// 容忍:那是 runner 把别的任务的消息算到了这个任务上。\n\t\t\t\t\t\t\tawait client.refreshMessages(taskId).catch((error: unknown) => {\n\t\t\t\t\t\t\t\tif (isCrossTaskViolation(error)) throw error;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (response.status === \"cancelled\") {\n\t\t\t\t\t\t\t\tthrow abortLikeError(\"agent task run was cancelled\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t\t\t// 取消先于 run 到达:runner 以 task_terminal 拒绝启动。父侧确实请求过取消,\n\t\t\t\t\t\t\t// 因此仍按取消类错误结算(与\"aborted 终局\"同一分类),不落成 failed。\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tsignal.aborted &&\n\t\t\t\t\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t\t\t(error as { code?: unknown }).code === \"task_terminal\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow abortLikeError(`agent task run was cancelled before start: ${abortReasonText(signal)}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.finally(() => client.releaseRun(taskId, runId));\n\t\t\t\t},\n\t\t\t\tcancel: (reason?: string): Promise<void> => client.cancelTask(taskId, reason),\n\t\t\t\tdispose: async (): Promise<void> => {\n\t\t\t\t\tliveTaskIds.delete(taskId);\n\t\t\t\t\tawait client.callForTask(taskId, { op: \"dispose\" });\n\t\t\t\t\tclient.dropTask(taskId);\n\t\t\t\t},\n\t\t\t};\n\t\t\treturn host;\n\t\t},\n\t\tdispose: async (): Promise<void> => {\n\t\t\t// 宿主会话销毁时释放全部未 dispose 的任务(逐个容错,不阻断其余回收)。\n\t\t\tfor (const taskId of [...liveTaskIds]) {\n\t\t\t\tliveTaskIds.delete(taskId);\n\t\t\t\tawait client.callForTask(taskId, { op: \"dispose\" }).catch(() => {});\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Structural renderCall / renderResult for `subagent_run`
3
+ * (docs/design/子代理运行时设计.md §6, 2026-10-19 user ruling).
4
+ *
5
+ * Quiet transcript contract: while the tool runs, its card rides the group
6
+ * marker's live tail; after it settles the card stays hidden by the group.
7
+ * Both states must therefore stay one human-readable line when collapsed —
8
+ * never the raw pretty-printed args or the JSON result. Expanded (ctrl+o)
9
+ * adds the role description and per-task details.
10
+ *
11
+ * No `@agent-forge/tui` import: capability plugins ship self-contained and the
12
+ * host accepts structural components only (tool-definition.ts hosting
13
+ * boundary; goal/plan/alignment precedent).
14
+ */
15
+ interface ThemeLike {
16
+ readonly fg: (color: string, text: string) => string;
17
+ }
18
+ interface RenderContextLike {
19
+ readonly args?: unknown;
20
+ readonly expanded?: boolean;
21
+ }
22
+ interface ToolResultTextPartLike {
23
+ readonly type: string;
24
+ readonly text?: string;
25
+ }
26
+ interface ToolResultLike {
27
+ readonly content: readonly ToolResultTextPartLike[];
28
+ }
29
+ interface RenderResultOptionsLike {
30
+ readonly expanded: boolean;
31
+ readonly isPartial: boolean;
32
+ }
33
+ interface StructuralComponent {
34
+ render(width: number): string[];
35
+ invalidate(): void;
36
+ }
37
+ /**
38
+ * The single collapsed call line: label, background marker, role, task count
39
+ * (only when it adds information) and the first non-empty prompt line.
40
+ */
41
+ export declare function subagentRunCallLine(args: unknown): string;
42
+ /**
43
+ * renderCall factory. `roleDescription` lets the expanded card show the role
44
+ * menu's one-line description without importing plugin state into this module.
45
+ */
46
+ export declare function createSubagentRunRenderCall(roleDescription?: (roleId: string) => string | undefined): (args: unknown, theme: ThemeLike, context: RenderContextLike) => StructuralComponent;
47
+ interface TaskView {
48
+ readonly taskId: string;
49
+ readonly status: string;
50
+ readonly messageCount?: number;
51
+ readonly reasonCode?: string;
52
+ readonly reason?: string;
53
+ }
54
+ /**
55
+ * The single result line shared by the collapsed summary and the expanded
56
+ * header. Keeps the role/task context from the call visible after settlement.
57
+ */
58
+ export declare function subagentRunResultLine(args: unknown, tasks: readonly TaskView[]): string;
59
+ /**
60
+ * renderResult: collapsed stays empty for successful/background tickets (the
61
+ * call line is the one visible line in the live tail). A failed task is never
62
+ * silent (D-083): its status rides one warning/error-colored line. Expanded
63
+ * returns the readable task detail.
64
+ */
65
+ export declare function subagentRunResultRenderer(result: ToolResultLike, options: RenderResultOptionsLike, theme: ThemeLike, context: RenderContextLike): StructuralComponent | undefined;
66
+ export {};
67
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,UAAU,SAAS;IAClB,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACrD;AAED,UAAU,iBAAiB;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,UAAU,sBAAsB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,cAAc;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACpD;AAED,UAAU,uBAAuB;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC5B;AAED,UAAU,mBAAmB;IAC5B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,UAAU,IAAI,IAAI,CAAC;CACnB;AAyJD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAWzD;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAC1C,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GACtD,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,KAAK,mBAAmB,CAatF;AAED,UAAU,QAAQ;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAmFD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,CAMvF;AAQD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACxC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,iBAAiB,GACxB,mBAAmB,GAAG,SAAS,CAuBjC","sourcesContent":["/**\n * Structural renderCall / renderResult for `subagent_run`\n * (docs/design/子代理运行时设计.md §6, 2026-10-19 user ruling).\n *\n * Quiet transcript contract: while the tool runs, its card rides the group\n * marker's live tail; after it settles the card stays hidden by the group.\n * Both states must therefore stay one human-readable line when collapsed —\n * never the raw pretty-printed args or the JSON result. Expanded (ctrl+o)\n * adds the role description and per-task details.\n *\n * No `@agent-forge/tui` import: capability plugins ship self-contained and the\n * host accepts structural components only (tool-definition.ts hosting\n * boundary; goal/plan/alignment precedent).\n */\n\ninterface ThemeLike {\n\treadonly fg: (color: string, text: string) => string;\n}\n\ninterface RenderContextLike {\n\treadonly args?: unknown;\n\treadonly expanded?: boolean;\n}\n\ninterface ToolResultTextPartLike {\n\treadonly type: string;\n\treadonly text?: string;\n}\n\ninterface ToolResultLike {\n\treadonly content: readonly ToolResultTextPartLike[];\n}\n\ninterface RenderResultOptionsLike {\n\treadonly expanded: boolean;\n\treadonly isPartial: boolean;\n}\n\ninterface StructuralComponent {\n\trender(width: number): string[];\n\tinvalidate(): void;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Collapse whitespace so multi-line prompts stay on the single-line card. */\nfunction oneLine(value: string): string {\n\treturn value.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Simplified East Asian width table: the CJK blocks prompts realistically use\n * count as 2 columns each; every other code point counts as 1. Combining marks\n * and ambiguous widths fall back to 1, the safe (narrower) default.\n */\nfunction isWideCodePoint(code: number): boolean {\n\treturn (\n\t\t(code >= 0x1100 && code <= 0x115f) ||\n\t\t(code >= 0x2e80 && code <= 0xa4cf) ||\n\t\t(code >= 0xac00 && code <= 0xd7a3) ||\n\t\t(code >= 0xf900 && code <= 0xfaff) ||\n\t\t(code >= 0xfe30 && code <= 0xfe4f) ||\n\t\t(code >= 0xff00 && code <= 0xff60) ||\n\t\t(code >= 0xffe0 && code <= 0xffe6) ||\n\t\t(code >= 0x20000 && code <= 0x3fffd)\n\t);\n}\n\nfunction displayWidth(value: string): number {\n\tlet columns = 0;\n\tfor (const character of value) columns += isWideCodePoint(character.codePointAt(0) ?? 0) ? 2 : 1;\n\treturn columns;\n}\n\n/** Cut one logical line to the terminal width, ending with an ellipsis. */\nfunction truncateLine(value: string, width: number): string {\n\tif (width <= 0 || displayWidth(value) <= width) return value;\n\tconst budget = width - 1;\n\tlet row = \"\";\n\tlet columns = 0;\n\tfor (const character of value) {\n\t\tconst cost = isWideCodePoint(character.codePointAt(0) ?? 0) ? 2 : 1;\n\t\tif (columns + cost > budget) break;\n\t\trow += character;\n\t\tcolumns += cost;\n\t}\n\treturn `${row}…`;\n}\n\n/** Fold one logical line into rows of at most `width` display columns. */\nfunction wrapLine(line: string, width: number): string[] {\n\tif (width <= 0) return [line];\n\tconst rows: string[] = [];\n\tlet row = \"\";\n\tlet columns = 0;\n\tfor (const character of line) {\n\t\tconst cost = isWideCodePoint(character.codePointAt(0) ?? 0) ? 2 : 1;\n\t\tif (row !== \"\" && columns + cost > width) {\n\t\t\trows.push(row);\n\t\t\trow = character;\n\t\t\tcolumns = cost;\n\t\t} else {\n\t\t\trow += character;\n\t\t\tcolumns += cost;\n\t\t}\n\t}\n\trows.push(row);\n\treturn rows;\n}\n\n/** One physical line whose overflow is cut, not wrapped. */\nclass OneLineComponent implements StructuralComponent {\n\tprivate readonly text: string;\n\tprivate readonly theme: ThemeLike;\n\tprivate readonly color: string;\n\tprivate cachedWidth: number | undefined;\n\tprivate cachedRows: string[] | undefined;\n\n\tconstructor(text: string, theme: ThemeLike, color: string) {\n\t\tthis.text = text;\n\t\tthis.theme = theme;\n\t\tthis.color = color;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (this.cachedRows !== undefined && this.cachedWidth === width) return this.cachedRows;\n\t\tthis.cachedRows = [this.theme.fg(this.color, truncateLine(this.text, width))];\n\t\tthis.cachedWidth = width;\n\t\treturn this.cachedRows;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedRows = undefined;\n\t}\n}\n\n/** Multi-line detail block; rows are cached per width like the goal renderer. */\nclass TextBlockComponent implements StructuralComponent {\n\tprivate readonly text: string;\n\tprivate readonly theme: ThemeLike;\n\tprivate readonly color: string;\n\tprivate readonly rowsByWidth = new Map<number, string[]>();\n\n\tconstructor(text: string, theme: ThemeLike, color: string) {\n\t\tthis.text = text;\n\t\tthis.theme = theme;\n\t\tthis.color = color;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst cached = this.rowsByWidth.get(width);\n\t\tif (cached) return cached;\n\t\tconst rows: string[] = [];\n\t\tfor (const line of this.text.split(\"\\n\")) {\n\t\t\tfor (const row of wrapLine(line, width)) rows.push(this.theme.fg(this.color, row));\n\t\t}\n\t\tthis.rowsByWidth.set(width, rows);\n\t\treturn rows;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.rowsByWidth.clear();\n\t}\n}\n\n/** Deliberately renders nothing: a collapsed result stays out of the live tail. */\nclass EmptyComponent implements StructuralComponent {\n\trender(): string[] {\n\t\treturn [];\n\t}\n\n\tinvalidate(): void {}\n}\n\nfunction promptList(value: unknown): string[] {\n\tif (!Array.isArray(value)) return [];\n\tconst prompts: string[] = [];\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\") continue;\n\t\tconst line = oneLine(item);\n\t\tif (line !== \"\") prompts.push(line);\n\t}\n\treturn prompts;\n}\n\nfunction readRole(args: unknown): string | undefined {\n\tif (!isRecord(args)) return undefined;\n\tconst role = args.role;\n\treturn typeof role === \"string\" && role.trim() !== \"\" ? role.trim() : undefined;\n}\n\n/**\n * The single collapsed call line: label, background marker, role, task count\n * (only when it adds information) and the first non-empty prompt line.\n */\nexport function subagentRunCallLine(args: unknown): string {\n\tconst record = isRecord(args) ? args : {};\n\tconst segments = [\"创建子代理\"];\n\tif (record.background === true) segments.push(\"后台\");\n\tconst role = readRole(record);\n\tif (role !== undefined) segments.push(role);\n\tconst prompts = promptList(record.prompts);\n\tif (prompts.length > 1) segments.push(`${prompts.length} 个任务`);\n\tconst first = prompts[0];\n\tif (first !== undefined) segments.push(first);\n\treturn segments.join(\" · \");\n}\n\n/**\n * renderCall factory. `roleDescription` lets the expanded card show the role\n * menu's one-line description without importing plugin state into this module.\n */\nexport function createSubagentRunRenderCall(\n\troleDescription?: (roleId: string) => string | undefined,\n): (args: unknown, theme: ThemeLike, context: RenderContextLike) => StructuralComponent {\n\treturn (args, theme, context) => {\n\t\tconst line = subagentRunCallLine(args);\n\t\tif (context.expanded !== true) {\n\t\t\treturn new OneLineComponent(line, theme, \"toolOutput\");\n\t\t}\n\t\tconst role = readRole(args);\n\t\tconst description = role === undefined ? undefined : roleDescription?.(role);\n\t\tif (description === undefined || description.trim() === \"\") {\n\t\t\treturn new TextBlockComponent(line, theme, \"toolOutput\");\n\t\t}\n\t\treturn new TextBlockComponent(`${line}\\n角色:${role} — ${oneLine(description)}`, theme, \"toolOutput\");\n\t};\n}\n\ninterface TaskView {\n\treadonly taskId: string;\n\treadonly status: string;\n\treadonly messageCount?: number;\n\treadonly reasonCode?: string;\n\treadonly reason?: string;\n}\n\ninterface ResultView {\n\treadonly background: boolean;\n\treadonly tasks: readonly TaskView[];\n}\n\n/**\n * Shape-gate the tool payload. Anything that is not this tool's JSON result\n * (progress text, error text, foreign data) returns undefined so the host\n * fallback keeps it visible — never silently swallowed.\n */\nfunction parseResultView(text: string): ResultView | undefined {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!isRecord(parsed) || !Array.isArray(parsed.tasks)) return undefined;\n\tconst tasks: TaskView[] = [];\n\tfor (const item of parsed.tasks) {\n\t\tif (!isRecord(item)) continue;\n\t\tconst taskId = typeof item.taskId === \"string\" ? item.taskId : \"\";\n\t\tif (parsed.background === true) {\n\t\t\ttasks.push({ taskId, status: \"submitted\" });\n\t\t\tcontinue;\n\t\t}\n\t\ttasks.push({\n\t\t\ttaskId,\n\t\t\tstatus: typeof item.status === \"string\" ? item.status : \"unknown\",\n\t\t\t...(typeof item.messageCount === \"number\" ? { messageCount: item.messageCount } : {}),\n\t\t\t...(typeof item.reasonCode === \"string\" ? { reasonCode: item.reasonCode } : {}),\n\t\t\t...(typeof item.reason === \"string\" ? { reason: item.reason } : {}),\n\t\t});\n\t}\n\treturn { background: parsed.background === true, tasks };\n}\n\nconst STATUS_LABELS: Record<string, string> = {\n\tqueued: \"排队\",\n\trunning: \"运行中\",\n\tsucceeded: \"成功\",\n\tfailed: \"失败\",\n\tcancelled: \"已取消\",\n\ttimed_out: \"超时\",\n\tinterrupted: \"已中断\",\n\tincomplete: \"未完成\",\n\trejected: \"已拒绝\",\n\tsubmitted: \"已提交\",\n\tunknown: \"未知\",\n};\n\nfunction statusLabel(status: string): string {\n\treturn STATUS_LABELS[status] ?? status;\n}\n\nfunction statusSummary(tasks: readonly TaskView[]): string {\n\tif (tasks.length === 0) return \"无任务\";\n\tconst counts = new Map<string, number>();\n\tfor (const task of tasks) counts.set(task.status, (counts.get(task.status) ?? 0) + 1);\n\tif (counts.size === 1) {\n\t\tconst status = tasks[0]?.status ?? \"unknown\";\n\t\treturn status === \"succeeded\" ? \"全部成功\" : statusLabel(status);\n\t}\n\treturn [...counts.entries()].map(([status, count]) => `${count} ${statusLabel(status)}`).join(\" · \");\n}\n\n/** Short task handle for the expanded card (`...:1:85c146d8` → `85c146d8`). */\nfunction shortTaskId(taskId: string): string {\n\tif (taskId === \"\") return \"(未创建)\";\n\tconst parts = taskId.split(\":\");\n\treturn parts[parts.length - 1] ?? taskId;\n}\n\nfunction taskLine(task: TaskView): string {\n\tconst parts = [` - ${shortTaskId(task.taskId)} [${statusLabel(task.status)}]`];\n\tif (task.messageCount !== undefined) parts.push(`${task.messageCount} 条消息`);\n\tif (task.reasonCode !== undefined) parts.push(task.reasonCode);\n\tif (task.reason !== undefined) parts.push(task.reason);\n\treturn parts.join(\" · \");\n}\n\n/**\n * The single result line shared by the collapsed summary and the expanded\n * header. Keeps the role/task context from the call visible after settlement.\n */\nexport function subagentRunResultLine(args: unknown, tasks: readonly TaskView[]): string {\n\tconst segments = [\"创建子代理\"];\n\tconst role = readRole(args);\n\tif (role !== undefined) segments.push(role);\n\tsegments.push(`${tasks.length} 个任务`, statusSummary(tasks));\n\treturn segments.join(\" · \");\n}\n\nconst FAILURE_STATUSES = new Set([\"failed\", \"rejected\", \"timed_out\"]);\n\nfunction statusColor(tasks: readonly TaskView[]): string {\n\treturn tasks.some((task) => FAILURE_STATUSES.has(task.status)) ? \"error\" : \"warning\";\n}\n\n/**\n * renderResult: collapsed stays empty for successful/background tickets (the\n * call line is the one visible line in the live tail). A failed task is never\n * silent (D-083): its status rides one warning/error-colored line. Expanded\n * returns the readable task detail.\n */\nexport function subagentRunResultRenderer(\n\tresult: ToolResultLike,\n\toptions: RenderResultOptionsLike,\n\ttheme: ThemeLike,\n\tcontext: RenderContextLike,\n): StructuralComponent | undefined {\n\tconst text = result.content.find((part) => part.type === \"text\")?.text;\n\tif (text === undefined || text === \"\") return undefined;\n\tconst view = parseResultView(text);\n\tif (view === undefined) {\n\t\t// Partial progress is process noise on the one-line card. A final\n\t\t// non-JSON result is usually the error text: keep the host fallback so\n\t\t// failures stay visible (D-083 failure visibility).\n\t\treturn options.isPartial ? new EmptyComponent() : undefined;\n\t}\n\tif (!options.expanded) {\n\t\tif (view.background || view.tasks.every((task) => task.status === \"succeeded\")) {\n\t\t\treturn new EmptyComponent();\n\t\t}\n\t\treturn new OneLineComponent(subagentRunResultLine(context.args, view.tasks), theme, statusColor(view.tasks));\n\t}\n\tconst lines = [subagentRunResultLine(context.args, view.tasks)];\n\tif (view.background) {\n\t\tfor (const task of view.tasks) lines.push(` - ${shortTaskId(task.taskId)} 后台运行,结算后自动回注`);\n\t} else {\n\t\tfor (const task of view.tasks) lines.push(taskLine(task));\n\t}\n\treturn new TextBlockComponent(lines.join(\"\\n\"), theme, \"toolOutput\");\n}\n"]}