negotium 0.1.37 → 0.1.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +19 -0
  2. package/dist/agent-helpers.js +15637 -5674
  3. package/dist/agent-helpers.js.map +85 -37
  4. package/dist/browser-runtime.js +1600 -0
  5. package/dist/browser-runtime.js.map +28 -0
  6. package/dist/hosted-agent.js +8 -8
  7. package/dist/hosted-agent.js.map +6 -5
  8. package/dist/main.js +3790 -3113
  9. package/dist/main.js.map +33 -29
  10. package/dist/mcp-factories.js +15141 -301
  11. package/dist/mcp-factories.js.map +100 -7
  12. package/dist/prompts.js +117 -49
  13. package/dist/prompts.js.map +3 -3
  14. package/dist/query-runtime.js +310 -1
  15. package/dist/query-runtime.js.map +10 -5
  16. package/dist/runtime/src/agents/archiver.ts +407 -296
  17. package/dist/runtime/src/agents/mcp-tools/ask-user.ts +440 -274
  18. package/dist/runtime/src/agents/mcp-tools/self-config.ts +139 -65
  19. package/dist/runtime/src/agents/mcp-tools/spawn-subagent.ts +1037 -816
  20. package/dist/runtime/src/agents/public-helpers.ts +82 -0
  21. package/dist/runtime/src/agents/self-config-core.ts +574 -278
  22. package/dist/runtime/src/agents/topic-cleanup.ts +167 -129
  23. package/dist/runtime/src/index.ts +4 -1
  24. package/dist/runtime/src/mcp/factories/index.ts +9 -0
  25. package/dist/runtime/src/mcp/session-comm/topic-catalog.ts +132 -0
  26. package/dist/runtime/src/mcp/session-comm/topics.ts +23 -57
  27. package/dist/runtime/src/platform/mcp-config.ts +2 -4
  28. package/dist/runtime/src/platform/playwright/browser-processes.ts +3 -2
  29. package/dist/runtime/src/platform/playwright/capability.ts +5 -0
  30. package/dist/runtime/src/platform/playwright/manager.ts +380 -66
  31. package/dist/runtime/src/platform/playwright/public-runtime.ts +45 -0
  32. package/dist/runtime/src/platform/playwright/transport-probe.ts +89 -0
  33. package/dist/runtime/src/prompts/builders.ts +192 -51
  34. package/dist/runtime/src/query/active-rooms.ts +2 -0
  35. package/dist/runtime/src/query/public-runtime.ts +8 -0
  36. package/dist/runtime/src/query/state.ts +69 -33
  37. package/dist/runtime/src/query/types.ts +1 -0
  38. package/dist/runtime/src/runtime/playwright-turn-abort.ts +59 -0
  39. package/dist/runtime/src/runtime/turn-event-stream.ts +23 -6
  40. package/dist/runtime/src/runtime/turn-runner.ts +6 -1
  41. package/dist/runtime/src/version.ts +1 -1
  42. package/dist/types/packages/core/src/agents/api-topic-agent-switch.d.ts +38 -0
  43. package/dist/types/packages/core/src/agents/archiver.d.ts +52 -16
  44. package/dist/types/packages/core/src/agents/mcp-tools/ask-user.d.ts +75 -4
  45. package/dist/types/packages/core/src/agents/mcp-tools/self-config.d.ts +17 -0
  46. package/dist/types/packages/core/src/agents/mcp-tools/spawn-subagent.d.ts +112 -25
  47. package/dist/types/packages/core/src/agents/public-helpers.d.ts +7 -0
  48. package/dist/types/packages/core/src/agents/self-config-core.d.ts +185 -0
  49. package/dist/types/packages/core/src/agents/topic-cleanup.d.ts +30 -24
  50. package/dist/types/packages/core/src/mcp/factories/index.d.ts +1 -0
  51. package/dist/types/packages/core/src/mcp/session-comm/topic-catalog.d.ts +46 -0
  52. package/dist/types/packages/core/src/platform/mcp-config.d.ts +2 -1
  53. package/dist/types/packages/core/src/platform/playwright/capability.d.ts +1 -0
  54. package/dist/types/packages/core/src/platform/playwright/manager.d.ts +65 -5
  55. package/dist/types/packages/core/src/platform/playwright/public-runtime.d.ts +4 -0
  56. package/dist/types/packages/core/src/platform/playwright/transport-probe.d.ts +13 -0
  57. package/dist/types/packages/core/src/prompts/builders.d.ts +29 -3
  58. package/dist/types/packages/core/src/query/active-rooms.d.ts +2 -0
  59. package/dist/types/packages/core/src/query/public-runtime.d.ts +1 -0
  60. package/dist/types/packages/core/src/query/state.d.ts +13 -0
  61. package/dist/types/packages/core/src/query/types.d.ts +2 -1
  62. package/dist/types/packages/core/src/runtime/playwright-turn-abort.d.ts +12 -0
  63. package/dist/types/packages/core/src/version.d.ts +1 -1
  64. package/package.json +6 -1
@@ -712,21 +712,38 @@ export async function runTurnEventStream(
712
712
  // message supersedes the turn. Adapters clean up transient tool status
713
713
  // separately when they receive ai_aborted.
714
714
  emitPendingAssistantMessage();
715
- if (!silent) hub.broadcastAborted(topicId, queryId, wsAbortReason(control.abortReason));
716
715
  terminalEmitted = true;
717
- outcome = { kind: "aborted" };
716
+ if (control.abortReason === AbortReason.Infrastructure) {
717
+ // Infrastructure loss is a failed turn, not a user stop. Defer the
718
+ // terminal event and settlement to turn-runner's provider-error path
719
+ // so visible turns, asks, subagents, and Cron all receive one
720
+ // consistent error outcome.
721
+ outcome = {
722
+ kind: "provider-error",
723
+ error: control.abortError ?? "Required browser infrastructure failed",
724
+ };
725
+ } else {
726
+ if (!silent) hub.broadcastAborted(topicId, queryId, wsAbortReason(control.abortReason));
727
+ outcome = { kind: "aborted" };
728
+ }
718
729
  // Internal abort = this turn is being replaced and (if it was a session
719
730
  // inject) re-queued — NOT a failure. Suppress the asker notification so
720
731
  // the caller doesn't get a spurious "Aborted" followed by the real reply
721
732
  // from the re-queued turn. Only External/stop notifies the asker.
722
- if (control.abortReason !== AbortReason.Internal) {
723
- deliverAskError(queryId, topicTitle, "Aborted");
733
+ if (
734
+ control.abortReason !== AbortReason.Internal &&
735
+ control.abortReason !== AbortReason.Infrastructure
736
+ ) {
737
+ const abortError = control.abortError ?? "Aborted";
738
+ deliverAskError(queryId, topicTitle, abortError);
724
739
  void settleSubagentFailure(queryId, "중지됨 (사용자가 실행을 멈췄습니다)");
725
740
  } else {
726
741
  // The replay receives a new queryId and registers a fresh callback.
727
742
  // Drop the superseded mapping now so it cannot leak until TTL expiry.
728
- const { resolveAskCallback } = await import("#runtime/ask-callbacks");
729
- resolveAskCallback(queryId);
743
+ if (control.abortReason === AbortReason.Internal) {
744
+ const { resolveAskCallback } = await import("#runtime/ask-callbacks");
745
+ resolveAskCallback(queryId);
746
+ }
730
747
  }
731
748
  }
732
749
  } catch (err) {
@@ -58,6 +58,7 @@ import {
58
58
  import { buildMentionOnlyChannelPrompt } from "#runtime/channel-context";
59
59
  import { classifyAgentError, stringifyError } from "#runtime/errors";
60
60
  import { withTurnSilenceHeartbeat } from "#runtime/event-heartbeat";
61
+ import { trackPlaywrightTurn, untrackPlaywrightTurn } from "#runtime/playwright-turn-abort";
61
62
  import { getTopicConfig } from "#runtime/topic-config";
62
63
  import { runTurnEventStream, type StreamAgentOutcome } from "#runtime/turn-event-stream";
63
64
  import {
@@ -1289,6 +1290,7 @@ export function startAiTurn(params: StartAiTurnParams): string | null {
1289
1290
  if (!playwrightCapability) {
1290
1291
  throw new Error("browser MCP capability was not registered");
1291
1292
  }
1293
+ trackPlaywrightTurn(playwrightInstanceKey, control);
1292
1294
  } catch (err) {
1293
1295
  logger.warn(
1294
1296
  { topicId, err },
@@ -1361,7 +1363,10 @@ export function startAiTurn(params: StartAiTurnParams): string | null {
1361
1363
  peerBridge,
1362
1364
  });
1363
1365
  } finally {
1364
- if (playwrightInstanceKey) unpinPlaywrightInstance(playwrightInstanceKey);
1366
+ if (playwrightInstanceKey) {
1367
+ untrackPlaywrightTurn(playwrightInstanceKey, control);
1368
+ unpinPlaywrightInstance(playwrightInstanceKey);
1369
+ }
1365
1370
  }
1366
1371
  }
1367
1372
  // Provider streams can stay silent while reasoning, starting MCPs, or
@@ -1 +1 @@
1
- export const NEGOTIUM_VERSION = "0.1.37";
1
+ export const NEGOTIUM_VERSION = "0.1.39";
@@ -0,0 +1,38 @@
1
+ import { type TopicConfig } from "../storage/api-topic-config";
2
+ import type { AgentKind, EffortLevel } from "../types";
3
+ export type ApiTopicSwitchOutcome = {
4
+ kind: "fresh";
5
+ agent: AgentKind;
6
+ reason: "no-history" | "bridge-failed";
7
+ } | {
8
+ kind: "bridged";
9
+ agent: AgentKind;
10
+ bridgedSessionId: string;
11
+ rolloutPath: string;
12
+ };
13
+ export type ApiTopicSwitchResult = {
14
+ ok: true;
15
+ outcome: ApiTopicSwitchOutcome;
16
+ } | {
17
+ ok: false;
18
+ error: string;
19
+ };
20
+ export interface SwitchApiTopicAgentOptions {
21
+ topicId: string;
22
+ topicTitle: string;
23
+ userId: string;
24
+ fromAgent?: AgentKind;
25
+ agent: AgentKind;
26
+ cwd: string;
27
+ config: TopicConfig;
28
+ /** Topic base values used when config has no explicit override. */
29
+ defaultModel?: string;
30
+ defaultEffort?: EffortLevel;
31
+ reason: string;
32
+ }
33
+ /**
34
+ * API-topic equivalent of `switchTopicAgent`: all web/MCP agent changes must
35
+ * pass through this path so the synthetic SDK rollout, unified-log manifest,
36
+ * and durable topic session stay in sync.
37
+ */
38
+ export declare function switchApiTopicAgent(opts: SwitchApiTopicAgentOptions): ApiTopicSwitchResult;
@@ -1,6 +1,6 @@
1
- import type { AgentKind } from "../types";
2
- import type { BackgroundSessionDto } from "../types/api";
3
- export declare function listActiveMemoryArchiverSessions(userId: string): BackgroundSessionDto[];
1
+ import { type AgentDef } from "../prompts/builders";
2
+ import type { AgentKind, AgentQueryOptions, UnifiedEvent } from "../types";
3
+ import type { BackgroundSessionDto, MessageDto } from "../types/api";
4
4
  export interface RunArchiverTurnParams {
5
5
  /** Stringified user id (route layer hands us strings). */
6
6
  userId: string;
@@ -23,17 +23,53 @@ export interface RunArchiverTurnParams {
23
23
  /** Called once when an accepted background turn settles. */
24
24
  onSettled?: (success: boolean) => void;
25
25
  }
26
- /**
27
- * Fire a background wiki-archiver turn for a deleted topic or active idle
28
- * snapshot.
29
- *
30
- * Reads the forensic archive file produced by `archiveTopicMessages` and
31
- * distils it into the **shared** wiki (summaries / articles / topic brief /
32
- * indexes / skills) via the wiki MCP, which the turn launches in topic-id mode
33
- * so its writes land in the same root normal forum turns query.
34
- *
35
- * Fire-and-forget: the async generator is drained on a detached promise so the
36
- * caller's HTTP response returns immediately. Every failure is best-effort and
37
- * logged only — a broken archiver must never block or fail a topic deletion.
38
- */
26
+ export interface ArchiverStorageHost {
27
+ getWikiDir(): string;
28
+ fileExists(path: string): boolean;
29
+ listDirectory(path: string): string[];
30
+ readTextFile(path: string): string;
31
+ fileSize(path: string): number;
32
+ fileModifiedAt(path: string): number;
33
+ getGeneralTopicId(userId: string): string;
34
+ getTopicBrief(topicId: string): {
35
+ briefMd: string;
36
+ } | null;
37
+ setTopicBrief(topicId: string, fields: {
38
+ briefMd: string;
39
+ latestSummaryMd?: string;
40
+ summaryDate?: string;
41
+ }): void;
42
+ }
43
+ export interface ArchiverMessagingHost {
44
+ appendMessage(message: MessageDto): void;
45
+ broadcastMessage(topicId: string, message: MessageDto): void;
46
+ }
47
+ export interface ArchiverConfigHost {
48
+ readonly workspaceDir: string;
49
+ readonly completedSessionRetentionMs: number;
50
+ loadAgentDefinition(): AgentDef;
51
+ sanitizeTopicName(topicTitle: string): string;
52
+ createId(): string;
53
+ now(): Date;
54
+ schedule(callback: () => void, delayMs: number): unknown;
55
+ cancelScheduled(handle: unknown): void;
56
+ unrefScheduled?(handle: unknown): void;
57
+ info(context: Record<string, unknown>, message: string): void;
58
+ warn(context: Record<string, unknown>, message: string): void;
59
+ }
60
+ export interface ArchiverAgentRuntimeHost {
61
+ run(options: AgentQueryOptions): AsyncIterable<UnifiedEvent>;
62
+ }
63
+ export interface ArchiverHost {
64
+ storage: ArchiverStorageHost;
65
+ messaging: ArchiverMessagingHost;
66
+ config: ArchiverConfigHost;
67
+ agentRuntime: ArchiverAgentRuntimeHost;
68
+ }
69
+ export interface ArchiverRuntime {
70
+ runArchiverTurn(params: RunArchiverTurnParams): boolean;
71
+ listActiveMemoryArchiverSessions(userId: string): BackgroundSessionDto[];
72
+ }
73
+ export declare function createArchiverRuntime(host: ArchiverHost): ArchiverRuntime;
39
74
  export declare function runArchiverTurn(params: RunArchiverTurnParams): boolean;
75
+ export declare function listActiveMemoryArchiverSessions(userId: string): BackgroundSessionDto[];
@@ -1,6 +1,8 @@
1
1
  import { type SharedMcpTool } from "./common";
2
+ import { type AskUserGateCardUpdate, type ClaimAskUserGateResult, type PrepareAskUserGateResult } from "../../storage/ask-user-gates";
3
+ import { type RuntimeProcessLease, type RuntimeProcessLeaseHandle } from "../../storage/runtime-process-leases";
2
4
  import type { AgentKind } from "../../types";
3
- import type { MessageDto } from "../../types/api";
5
+ import type { MessageDto, TopicDto } from "../../types/api";
4
6
  export type AskUserChoice = {
5
7
  label: string;
6
8
  description?: string;
@@ -20,8 +22,70 @@ export type AnswerAskUserQuestionResult = {
20
22
  ok: false;
21
23
  error: string;
22
24
  };
23
- export declare function startAskUserQuestionGateOwner(): void;
24
- export declare function stopAskUserQuestionGateOwner(): void;
25
+ export interface AskUserRuntimeHost {
26
+ messaging: {
27
+ persistence: {
28
+ getMessage(topicId: string, messageId: string): MessageDto | null | undefined;
29
+ appendMessage(message: MessageDto): void;
30
+ };
31
+ publication: {
32
+ publishMessage(topicId: string, message: MessageDto): void;
33
+ publishCardUpdate(update: AskUserGateCardUpdate): void;
34
+ };
35
+ };
36
+ topics: {
37
+ getTopic(topicId: string): Pick<TopicDto, "participants"> | null | undefined;
38
+ getConfig(topicId: string): {
39
+ model?: string;
40
+ } | undefined;
41
+ };
42
+ durability: {
43
+ gates: {
44
+ prepare(args: {
45
+ gateId: string;
46
+ topicId: string;
47
+ queryId?: string;
48
+ idempotencyKey: string;
49
+ bodyHash: string;
50
+ messageId: string;
51
+ ownerId: string;
52
+ now: string;
53
+ }): PrepareAskUserGateResult;
54
+ claimAndSelect(args: {
55
+ topicId: string;
56
+ messageId: string;
57
+ label: string;
58
+ userId: string;
59
+ ownerId: string;
60
+ source: string;
61
+ now: string;
62
+ }): ClaimAskUserGateResult;
63
+ cancel(topicId: string, messageId: string, ownerId: string, now: string): AskUserGateCardUpdate | null;
64
+ quarantine(gateId: string, ownerId: string, now: string): AskUserGateCardUpdate | null;
65
+ quarantineForeign(liveOwnerIds: ReadonlySet<string>, now: string): AskUserGateCardUpdate[];
66
+ };
67
+ processLeases: {
68
+ acquire(role: string, ownerId: string): RuntimeProcessLeaseHandle | null;
69
+ list(rolePrefix: string): RuntimeProcessLease[];
70
+ isAlive(lease: RuntimeProcessLease): boolean;
71
+ removeDead(rolePrefix: string): void;
72
+ };
73
+ };
74
+ runtime: {
75
+ ownerId: string;
76
+ createId(): string;
77
+ now(): string;
78
+ };
79
+ }
80
+ export interface AskUserRuntime {
81
+ startGateOwner(): void;
82
+ stopGateOwner(): void;
83
+ reconcilePendingGates(): number;
84
+ hasPendingQuestion(topicId: string, messageId: string): boolean;
85
+ answerPendingQuestion(topicId: string, messageId: string, label: string, userId: string): AnswerAskUserQuestionResult;
86
+ cancelPendingQuestions(topicId: string, queryId: string): void;
87
+ createToolDefinition(ctx: AskUserToolContext): SharedMcpTool;
88
+ }
25
89
  export declare function normalizeAskUserChoices(value: unknown): AskUserChoice[];
26
90
  export declare function normalizeAskUserQuestionInput(input: {
27
91
  question?: unknown;
@@ -32,8 +96,15 @@ export declare function normalizeAskUserQuestionInput(input: {
32
96
  } | {
33
97
  error: string;
34
98
  };
35
- export declare function hasPendingAskUserQuestion(topicId: string, messageId: string): boolean;
99
+ /**
100
+ * Create an isolated ask-user lifecycle over host-provided messaging, topic,
101
+ * durability, and runtime services.
102
+ */
103
+ export declare function createAskUserRuntime(host: AskUserRuntimeHost): AskUserRuntime;
104
+ export declare function startAskUserQuestionGateOwner(): void;
105
+ export declare function stopAskUserQuestionGateOwner(): void;
36
106
  export declare function reconcilePendingAskUserQuestionGates(): number;
107
+ export declare function hasPendingAskUserQuestion(topicId: string, messageId: string): boolean;
37
108
  /**
38
109
  * Host-neutral answer path for runtime ask cards. Web, terminal, Telegram, and
39
110
  * future adapters should call this rather than reimplementing pending-map and
@@ -0,0 +1,17 @@
1
+ import { type SharedMcpTool } from "./common";
2
+ import { SELF_CONFIG_MCP_KEY, type SelfConfigContext, type SelfConfigCore, type SelfConfigHost, type SelfConfigProductConfig } from "../self-config-core";
3
+ export type { SelfConfigContext };
4
+ export { SELF_CONFIG_MCP_KEY };
5
+ export declare const SELF_CONFIG_DERIVED_TOPIC_LIMIT = 5;
6
+ export interface SelfConfigRuntime {
7
+ readonly core: SelfConfigCore;
8
+ readonly mcpKey: string;
9
+ createToolDefinitions(ctx: SelfConfigContext | (() => SelfConfigContext)): SharedMcpTool[];
10
+ }
11
+ export interface SelfConfigRuntimeOptions {
12
+ host: SelfConfigHost;
13
+ product?: Partial<SelfConfigProductConfig>;
14
+ }
15
+ export declare function createSelfConfigRuntime(options: SelfConfigRuntimeOptions): SelfConfigRuntime;
16
+ export declare function createSelfConfigToolDefinitionsForCore(core: SelfConfigCore, ctx: SelfConfigContext | (() => SelfConfigContext)): SharedMcpTool[];
17
+ export declare function createSelfConfigToolDefinitions(ctx: SelfConfigContext | (() => SelfConfigContext)): SharedMcpTool[];
@@ -1,7 +1,12 @@
1
1
  import { type SharedMcpTool } from "./common";
2
2
  import { type AgentKind } from "../../types";
3
- import type { SubagentReportMode } from "../../types/api";
3
+ import type { MessageDto, SubagentCardDto, SubagentReportMode, TopicDto } from "../../types/api";
4
4
  export declare const MAX_SUBAGENT_DEPTH = 2;
5
+ export interface SubagentLifecycleLimits {
6
+ readonly maxDepth: number;
7
+ readonly maxLiveChildrenPerParent: number;
8
+ readonly maxPreparedChildrenPerParent: number;
9
+ }
5
10
  export interface SpawnSubagentToolContext {
6
11
  userId: string;
7
12
  topicId: string;
@@ -21,27 +26,109 @@ export interface SubagentWatch {
21
26
  queryId?: string;
22
27
  running: boolean;
23
28
  }
24
- /**
25
- * Walk the parent chain and count how many subagent ancestors this topic has.
26
- * Runs on every turn/MCP build, so it walks per-parent lookups (depth-capped)
27
- * instead of scanning the whole topic table.
28
- */
29
- export declare function computeSubagentDepth(topicId: string): number;
30
- export declare function canSpawnSubagentsFromTopic(topicId: string): boolean;
31
- /** Claim the watch for a finished child turn (delete-on-take). */
32
- export declare function takeSubagentWatch(queryId: string): SubagentWatch | null;
33
- /** Drop deferred/in-flight bookkeeping when a subagent room is hard-deleted. */
34
- export declare function cancelSubagentWatchForDeletedTopic(childTopicId: string): void;
35
- /** Settle a finished child run. NEVER rejects — call sites fire-and-forget. */
36
- export declare function settleSubagentSuccess(watch: SubagentWatch, finalText: string): Promise<void>;
37
- /** Settle a failed child run. NEVER rejects — call sites fire-and-forget. */
38
- export declare function settleSubagentFailure(queryId: string, reason: string): Promise<void>;
39
- /**
40
- * Boot-time sweep: watches don't survive a restart, so any card still marked
41
- * spawned/running belongs to a run whose completion can no longer be tracked.
42
- */
43
- export declare function sweepStaleSubagentCards(): void;
44
- export declare function subagentReportMode(childTopicId: string): SubagentReportMode;
45
- export declare function createSubagentManagementToolDefinitions(ctx: SubagentToolContext): SharedMcpTool[];
46
- export declare function createSpawnSubagentToolDefinition(ctx: SpawnSubagentToolContext): SharedMcpTool;
47
- export declare function createPrepareSubagentToolDefinition(ctx: SpawnSubagentToolContext): SharedMcpTool;
29
+ export interface SubagentLifecycleHost<TContext extends SpawnSubagentToolContext = SpawnSubagentToolContext> {
30
+ storage: {
31
+ getTopic(topicId: string): TopicDto | null | undefined;
32
+ listTopics(): TopicDto[];
33
+ getTopicMemoryOrigin(topicId: string): TopicDto | null;
34
+ upsertTopic(topic: TopicDto): void;
35
+ getMessage(topicId: string, messageId: string): MessageDto | null | undefined;
36
+ listSubagentMessages(): MessageDto[];
37
+ appendMessage(message: MessageDto, options?: {
38
+ notify?: boolean;
39
+ }): void;
40
+ updateSubagentCard(topicId: string, messageId: string, card: SubagentCardDto, editedAt: string): MessageDto | null;
41
+ publishMessage(topicId: string, message: MessageDto): void;
42
+ publishCardUpdate(topicId: string, messageId: string, update: {
43
+ subagentCard: SubagentCardDto;
44
+ editedAt: string;
45
+ }): void;
46
+ };
47
+ topic: {
48
+ createDerived(input: {
49
+ context: TContext;
50
+ parentTopicId: string;
51
+ userId: string;
52
+ name?: string;
53
+ agent?: AgentKind;
54
+ model?: string;
55
+ memoryTopicId?: string;
56
+ }): Promise<{
57
+ ok: true;
58
+ topic: TopicDto | null;
59
+ } | {
60
+ ok: false;
61
+ reason: "busy" | "title-conflict";
62
+ message?: string;
63
+ }>;
64
+ delete(topic: TopicDto, userId: string): Promise<void>;
65
+ };
66
+ task: {
67
+ dispatch(input: {
68
+ child: TopicDto;
69
+ parent: TopicDto;
70
+ userId: string;
71
+ prompt: string;
72
+ requestId: string;
73
+ onDispatched(queryId: string): void;
74
+ }): Promise<{
75
+ accepted: boolean;
76
+ error?: string;
77
+ }>;
78
+ };
79
+ sessionCommunication: {
80
+ notifyParent(input: {
81
+ watch: SubagentWatch;
82
+ prompt: string;
83
+ requestId: string;
84
+ }): Promise<boolean>;
85
+ listTellTargetIds(sourceTopicId: string): string[];
86
+ grantTellTarget(sourceTopicId: string, targetTopicId: string, grantedByTopicId: string): void;
87
+ revokeTellTarget(sourceTopicId: string, targetTopicId: string): boolean;
88
+ };
89
+ runtime: {
90
+ ownerId: string;
91
+ now(): string;
92
+ ownerIsAlive(ownerId: string): boolean;
93
+ childExecutionQueryId(childTopicId: string): string | null;
94
+ childExecutionIsRecoverable(childTopicId: string): boolean;
95
+ };
96
+ config: {
97
+ limits?: Partial<SubagentLifecycleLimits>;
98
+ resolveAgentModel(input: {
99
+ context: TContext;
100
+ agent: AgentKind;
101
+ model?: string;
102
+ hasOverride: boolean;
103
+ }): Promise<{
104
+ model?: string;
105
+ error?: string;
106
+ }>;
107
+ memoryFilenames(topic: TopicDto): string[];
108
+ };
109
+ }
110
+ export interface SubagentLifecycle<TContext extends SpawnSubagentToolContext = SpawnSubagentToolContext> {
111
+ computeSubagentDepth(topicId: string): number;
112
+ canSpawnSubagentsFromTopic(topicId: string): boolean;
113
+ takeSubagentWatch(queryId: string): SubagentWatch | null;
114
+ cancelSubagentWatchForDeletedTopic(childTopicId: string): void;
115
+ settleSubagentSuccess(watch: SubagentWatch, finalText: string): Promise<void>;
116
+ settleSubagentFailure(queryId: string, reason: string): Promise<void>;
117
+ sweepStaleSubagentCards(): void;
118
+ subagentReportMode(childTopicId: string): SubagentReportMode;
119
+ createSubagentManagementToolDefinitions(ctx: SubagentToolContext): SharedMcpTool[];
120
+ createSpawnSubagentToolDefinition(ctx: TContext): SharedMcpTool;
121
+ createPrepareSubagentToolDefinition(ctx: TContext): SharedMcpTool;
122
+ }
123
+ export declare function createSubagentLifecycle<TContext extends SpawnSubagentToolContext>(host: SubagentLifecycleHost<TContext>): SubagentLifecycle<TContext>;
124
+ export declare const computeSubagentDepth: (topicId: string) => number;
125
+ export declare const canSpawnSubagentsFromTopic: (topicId: string) => boolean;
126
+ export declare const takeSubagentWatch: (queryId: string) => SubagentWatch | null;
127
+ export declare const cancelSubagentWatchForDeletedTopic: (childTopicId: string) => void;
128
+ export declare const settleSubagentSuccess: (watch: SubagentWatch, finalText: string) => Promise<void>;
129
+ export declare const settleSubagentFailure: (queryId: string, reason: string) => Promise<void>;
130
+ export declare const sweepStaleSubagentCards: () => void;
131
+ export declare const subagentReportMode: (childTopicId: string) => SubagentReportMode;
132
+ export declare const createSubagentManagementToolDefinitions: (ctx: SubagentToolContext) => SharedMcpTool[];
133
+ export declare const createSpawnSubagentToolDefinition: (ctx: SpawnSubagentToolContext) => SharedMcpTool;
134
+ export declare const createPrepareSubagentToolDefinition: (ctx: SpawnSubagentToolContext) => SharedMcpTool;
@@ -1,9 +1,16 @@
1
+ export { type ArchiverAgentRuntimeHost, type ArchiverConfigHost, type ArchiverHost, type ArchiverMessagingHost, type ArchiverRuntime, type ArchiverStorageHost, createArchiverRuntime, type RunArchiverTurnParams, } from "./archiver";
1
2
  export { type AgentAuthHost, type AuthCheckResult, checkAgentAuth, checkAgentModelAuth, } from "./auth-check";
2
3
  export { acquireCodexSpawnLock, type CodexProcStamp, type CodexTreeHost, type CodexTreeLogger, type CodexTreeManager, type CodexTreeManagerOptions, createCodexTreeManager, findNewCodexChildren, killCodexTrees, killOwnedCodexTreesForShutdown, registerOwnedCodexPids, snapshotCodexChildren, unregisterOwnedCodexPids, withCodexSpawnSerial, } from "./codex-tree-kill";
3
4
  export { type AgentForkHelpers, type AgentForkHost, cleanupAgentFork, createAgentForkHelpers, type ForkAgentSessionOptions, type ForkHandle, forkAgentSession, } from "./fork";
4
5
  export { type ActiveTopicArchiveOptions, archiveActiveTopicForMemory, } from "./idle-archiver";
6
+ export { type AnswerAskUserQuestionResult, type AskUserChoice, type AskUserRuntime, type AskUserRuntimeHost, type AskUserToolContext, createAskUserRuntime, normalizeAskUserChoices, normalizeAskUserQuestionInput, } from "./mcp-tools/ask-user";
7
+ export { createSelfConfigRuntime, createSelfConfigToolDefinitionsForCore, type SelfConfigRuntime, type SelfConfigRuntimeOptions, } from "./mcp-tools/self-config";
8
+ export { createSubagentLifecycle, type SpawnSubagentToolContext, type SubagentLifecycle, type SubagentLifecycleHost, type SubagentLifecycleLimits, type SubagentToolContext, type SubagentWatch, } from "./mcp-tools/spawn-subagent";
5
9
  export { otiumVisualToolDefinitions, showPngTool, } from "./mcp-tools/visual-compat";
6
10
  export { showHtmlTool, showImageTool, showMermaidTool, showVideoTool, VISUALS_MCP_KEY, visualToolDefinitions, } from "./mcp-tools/visuals";
7
11
  export { MIN_MEMORY_ARCHIVE_EXCHANGES } from "./memory-archive-policy";
12
+ export { createSelfConfigCore, DEFAULT_SELF_CONFIG_PRODUCT, type SelfConfigAgentPolicy, type SelfConfigAgentSwitchOptions, type SelfConfigAgentSwitchResult, type SelfConfigContext, type SelfConfigCore, type SelfConfigCreateScheduleResult, type SelfConfigDerivedTopics, type SelfConfigField, type SelfConfigHost, type SelfConfigModelPolicy, type SelfConfigProductConfig, type SelfConfigResult, type SelfConfigRuntimeBoundary, type SelfConfigSchedule, type SelfConfigSchedules, type SelfConfigTopic, type SelfConfigTopicConfig, type SelfConfigTopicStore, } from "./self-config-core";
8
13
  export { resolveTaskEventScope, type TaskEventHost, type TaskEventScope, withTaskSnapshots, } from "./task-events";
14
+ export { buildNumberedDiffSummary, classifyShellToolName, formatToolUse, type NumberedDiffSummary, summarizeDisplayText, summarizeShellCommand, summarizeToolInput, type ToolCallSummaryInput, type ToolCallSummaryValue, } from "./tool-format";
15
+ export { cleanupTopicRollouts, cleanupTopicRolloutsFromEntries, createTopicLogMaintenance, type PurgeSessionRef, type PurgeTopicLogsOptions, purgeTopicLogs, type RotateTopicLogsOptions, type RotateTopicLogsResult, rotateTopicLogs, type TopicConversationEntry, type TopicLogMaintenance, type TopicLogMaintenanceHost, } from "./topic-cleanup";
9
16
  export { createVaultToolPolicy, isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool, VAULT_BROKER_REDIRECT_ERROR, type VaultToolPolicy, type VaultToolPolicyHost, } from "./vault-tool-policy";
@@ -0,0 +1,185 @@
1
+ import type { AgentKind, EffortLevel } from "../types";
2
+ export declare const SELF_CONFIG_MCP_KEY = "topic-config";
3
+ export declare const SELF_SCHEDULE_MAX_DELAY_SECONDS = 86400;
4
+ export declare const SELF_SCHEDULE_MAX_MESSAGE_LENGTH = 10000;
5
+ export declare const SELF_CONFIG_DERIVED_TOPIC_LIMIT = 5;
6
+ export type SelfConfigField = "agent" | "model" | "effort";
7
+ export interface SelfConfigContext {
8
+ topicId: string;
9
+ userId: string;
10
+ cwd?: string;
11
+ /** Raw current user request. Used to prevent autonomous MCP agent switches. */
12
+ currentUserPrompt?: string;
13
+ /** Called after a successful set_* so the caller can trigger a follow-up turn. */
14
+ onConfigChanged?: (field: SelfConfigField) => void;
15
+ }
16
+ export interface SelfConfigResult {
17
+ text: string;
18
+ isError?: boolean;
19
+ }
20
+ export interface SelfConfigTopic {
21
+ id: string;
22
+ title: string;
23
+ agent?: AgentKind;
24
+ defaultModel: string;
25
+ defaultEffort: EffortLevel;
26
+ participants: readonly {
27
+ userId: string;
28
+ }[];
29
+ }
30
+ export interface SelfConfigTopicConfig {
31
+ model?: string;
32
+ effort?: EffortLevel;
33
+ mcp?: string[];
34
+ agentLocked?: boolean;
35
+ modelLocked?: boolean;
36
+ effortLocked?: boolean;
37
+ }
38
+ export interface SelfConfigAgentPolicy {
39
+ defaultEffort?: EffortLevel;
40
+ validEfforts: readonly EffortLevel[];
41
+ validateModel(model: string): boolean;
42
+ validateEffort(effort: EffortLevel): boolean;
43
+ resolveModel(model: string | undefined): string;
44
+ }
45
+ export interface SelfConfigTopicStore {
46
+ getTopic(topicId: string): SelfConfigTopic | null;
47
+ getConfig(topicId: string): SelfConfigTopicConfig | undefined;
48
+ setConfig(topicId: string, config: SelfConfigTopicConfig): void;
49
+ }
50
+ export interface SelfConfigModelPolicy {
51
+ forAgent(agent: AgentKind): SelfConfigAgentPolicy;
52
+ owner(model: string): AgentKind | undefined;
53
+ checkAuth(agent: AgentKind, model: string, userId: string): {
54
+ ok: true;
55
+ } | {
56
+ ok: false;
57
+ error: string;
58
+ };
59
+ }
60
+ export interface SelfConfigRuntimeBoundary {
61
+ resolveWorkspaceDir(topicId: string): string;
62
+ switchAgent(options: SelfConfigAgentSwitchOptions): SelfConfigAgentSwitchResult;
63
+ configChanged(topicId: string, field: SelfConfigField): void;
64
+ }
65
+ export type SelfConfigAgentSwitchResult = {
66
+ ok: true;
67
+ outcome: {
68
+ kind: "fresh";
69
+ agent: AgentKind;
70
+ reason: "no-history" | "bridge-failed";
71
+ } | {
72
+ kind: "bridged";
73
+ agent: AgentKind;
74
+ bridgedSessionId: string;
75
+ rolloutPath: string;
76
+ };
77
+ } | {
78
+ ok: false;
79
+ error: string;
80
+ };
81
+ export interface SelfConfigAgentSwitchOptions {
82
+ topicId: string;
83
+ topicTitle: string;
84
+ userId: string;
85
+ fromAgent?: AgentKind;
86
+ agent: AgentKind;
87
+ cwd: string;
88
+ config: SelfConfigTopicConfig;
89
+ defaultModel?: string;
90
+ defaultEffort?: EffortLevel;
91
+ reason: string;
92
+ }
93
+ export interface SelfConfigDerivedTopics {
94
+ create(sourceTopicId: string, userId: string, copyHistory: boolean, options: {
95
+ name?: string;
96
+ }): Promise<SelfConfigTopic | null>;
97
+ link(topicId: string): string;
98
+ isTitleConflict(error: unknown): boolean;
99
+ isForkCompactionError(error: unknown): boolean;
100
+ }
101
+ export interface SelfConfigSchedules {
102
+ create(input: {
103
+ topicId: string;
104
+ userId: string;
105
+ message: string;
106
+ deliverAt: number;
107
+ now?: number;
108
+ }): SelfConfigCreateScheduleResult;
109
+ getPending(topicId: string): SelfConfigSchedule | null;
110
+ update(input: {
111
+ topicId: string;
112
+ scheduleId: string;
113
+ message?: string;
114
+ deliverAt?: number;
115
+ now?: number;
116
+ }): SelfConfigSchedule | null;
117
+ cancel(topicId: string, scheduleId: string): boolean;
118
+ }
119
+ export interface SelfConfigSchedule {
120
+ id: string;
121
+ topicId: string;
122
+ userId: string;
123
+ message: string;
124
+ deliverAt: number;
125
+ }
126
+ export type SelfConfigCreateScheduleResult = {
127
+ ok: true;
128
+ schedule: SelfConfigSchedule;
129
+ } | {
130
+ ok: false;
131
+ existing: SelfConfigSchedule;
132
+ };
133
+ /** Product-level limits and copy that are shared by policy and MCP wrappers. */
134
+ export interface SelfConfigProductConfig {
135
+ readonly mcpKey: string;
136
+ readonly scheduleMaxDelaySeconds: number;
137
+ readonly scheduleMaxMessageLength: number;
138
+ readonly derivedTopicLimit: number;
139
+ readonly toolDescriptions: Readonly<Record<string, string>>;
140
+ }
141
+ export interface SelfConfigHost {
142
+ topics: SelfConfigTopicStore;
143
+ models: SelfConfigModelPolicy;
144
+ runtime: SelfConfigRuntimeBoundary;
145
+ derivedTopics?: SelfConfigDerivedTopics;
146
+ schedules?: SelfConfigSchedules;
147
+ }
148
+ export interface SelfConfigCore {
149
+ readonly host: SelfConfigHost;
150
+ readonly product: SelfConfigProductConfig;
151
+ setModel(ctx: SelfConfigContext, model: string): SelfConfigResult;
152
+ getModel(ctx: SelfConfigContext): SelfConfigResult;
153
+ setAgent(ctx: SelfConfigContext, agent: AgentKind): SelfConfigResult;
154
+ getAgent(ctx: SelfConfigContext): SelfConfigResult;
155
+ setEffort(ctx: SelfConfigContext, effort: EffortLevel): SelfConfigResult;
156
+ getEffort(ctx: SelfConfigContext): SelfConfigResult;
157
+ scheduleContinue(ctx: SelfConfigContext, delaySeconds: number, message: string, nowMs?: number): SelfConfigResult;
158
+ getSchedule(ctx: SelfConfigContext, nowMs?: number): SelfConfigResult;
159
+ updateSchedule(ctx: SelfConfigContext, scheduleId: string, updates: {
160
+ delaySeconds?: number;
161
+ message?: string;
162
+ }, nowMs?: number): SelfConfigResult;
163
+ cancelSchedule(ctx: SelfConfigContext, scheduleId: string): SelfConfigResult;
164
+ spawnTopic(ctx: SelfConfigContext, name?: string): Promise<SelfConfigResult>;
165
+ forkTopic(ctx: SelfConfigContext, name?: string): Promise<SelfConfigResult>;
166
+ }
167
+ export declare const DEFAULT_SELF_CONFIG_PRODUCT: SelfConfigProductConfig;
168
+ export declare function createSelfConfigCore(host: SelfConfigHost, productOverrides?: Partial<SelfConfigProductConfig>): SelfConfigCore;
169
+ export declare const defaultSelfConfigHost: SelfConfigHost;
170
+ export declare const defaultSelfConfigCore: SelfConfigCore;
171
+ export declare function setSelfConfigModel(ctx: SelfConfigContext, model: string): SelfConfigResult;
172
+ export declare function getSelfConfigModel(ctx: SelfConfigContext): SelfConfigResult;
173
+ export declare function setSelfConfigAgent(ctx: SelfConfigContext, agent: AgentKind): SelfConfigResult;
174
+ export declare function getSelfConfigAgent(ctx: SelfConfigContext): SelfConfigResult;
175
+ export declare function setSelfConfigEffort(ctx: SelfConfigContext, effort: EffortLevel): SelfConfigResult;
176
+ export declare function getSelfConfigEffort(ctx: SelfConfigContext): SelfConfigResult;
177
+ export declare function scheduleSelfConfigContinue(ctx: SelfConfigContext, delaySeconds: number, message: string, nowMs?: number): SelfConfigResult;
178
+ export declare function getSelfConfigSchedule(ctx: SelfConfigContext, nowMs?: number): SelfConfigResult;
179
+ export declare function updateSelfConfigSchedule(ctx: SelfConfigContext, scheduleId: string, updates: {
180
+ delaySeconds?: number;
181
+ message?: string;
182
+ }, nowMs?: number): SelfConfigResult;
183
+ export declare function cancelSelfConfigSchedule(ctx: SelfConfigContext, scheduleId: string): SelfConfigResult;
184
+ export declare function spawnSelfConfigTopic(ctx: SelfConfigContext, name?: string): Promise<SelfConfigResult>;
185
+ export declare function forkSelfConfigTopic(ctx: SelfConfigContext, name?: string): Promise<SelfConfigResult>;