negotium 0.2.27 → 0.2.28

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 (42) hide show
  1. package/dist/agent-helpers.js +197 -113
  2. package/dist/agent-helpers.js.map +13 -13
  3. package/dist/hosted-agent.js +2 -2
  4. package/dist/hosted-agent.js.map +2 -2
  5. package/dist/main.js +1121 -506
  6. package/dist/main.js.map +43 -41
  7. package/dist/mcp-factories.js +291 -211
  8. package/dist/mcp-factories.js.map +13 -13
  9. package/dist/registry.js +2 -2
  10. package/dist/registry.js.map +2 -2
  11. package/dist/runtime/src/application/submit-runtime-gateway-turn.ts +8 -0
  12. package/dist/runtime/src/index.ts +6 -0
  13. package/dist/runtime/src/mcp/session-comm/default-host.ts +25 -6
  14. package/dist/runtime/src/mcp/session-comm/peer-forward.ts +14 -3
  15. package/dist/runtime/src/mcp/session-comm/server.ts +1 -1
  16. package/dist/runtime/src/mcp/session-comm/topics.ts +52 -16
  17. package/dist/runtime/src/mcp-runtime-host.ts +2 -2
  18. package/dist/runtime/src/node-host.ts +1 -1
  19. package/dist/runtime/src/runtime/turn-event-stream.ts +9 -1
  20. package/dist/runtime/src/runtime/turn-runner.ts +11 -2
  21. package/dist/runtime/src/storage/api-topics.ts +202 -26
  22. package/dist/runtime/src/storage/runtime-turn-requests.ts +26 -2
  23. package/dist/runtime/src/storage/token-stats.ts +27 -2
  24. package/dist/runtime/src/topics/create.ts +27 -1
  25. package/dist/runtime/src/topics/derive.ts +20 -6
  26. package/dist/runtime/src/topics/lifecycle.ts +2 -0
  27. package/dist/runtime/src/topics/personal-general.ts +28 -4
  28. package/dist/runtime/src/types/api.ts +7 -0
  29. package/dist/runtime/src/version.ts +1 -1
  30. package/dist/storage.js +138 -26
  31. package/dist/storage.js.map +4 -4
  32. package/dist/types/packages/core/src/mcp/session-comm/peer-forward.d.ts +7 -2
  33. package/dist/types/packages/core/src/runtime/turn-event-stream.d.ts +2 -0
  34. package/dist/types/packages/core/src/runtime/turn-runner.d.ts +3 -0
  35. package/dist/types/packages/core/src/storage/api-topics.d.ts +42 -3
  36. package/dist/types/packages/core/src/storage/runtime-turn-requests.d.ts +6 -0
  37. package/dist/types/packages/core/src/storage/token-stats.d.ts +2 -1
  38. package/dist/types/packages/core/src/topics/derive.d.ts +2 -0
  39. package/dist/types/packages/core/src/topics/personal-general.d.ts +4 -2
  40. package/dist/types/packages/core/src/types/api.d.ts +7 -0
  41. package/dist/types/packages/core/src/version.d.ts +1 -1
  42. package/package.json +1 -1
@@ -36,7 +36,12 @@ export interface RemoteReplyRoute {
36
36
  }
37
37
  export interface PeerSessionBridge {
38
38
  forward(args: PeerForwardArgs): Promise<PeerForwardResult>;
39
- sessions(userId: string, sourceQueryId?: string): Promise<PeerSessionsResult>;
39
+ /**
40
+ * `fromTopicId` names the asking room so the bridge can answer within that
41
+ * room's workspace. Without it the answer is the union of every attached
42
+ * workspace's nodes, which leaks one workspace's topology into another.
43
+ */
44
+ sessions(userId: string, sourceQueryId?: string, fromTopicId?: string): Promise<PeerSessionsResult>;
40
45
  reply(route: RemoteReplyRoute, sourceTitle: string, replyText: string, kind: "reply" | "error"): Promise<boolean>;
41
46
  }
42
47
  export declare function registerPeerSessionBridge(bridge: PeerSessionBridge): () => void;
@@ -55,5 +60,5 @@ export interface PeerSessionsResult {
55
60
  sessions?: PeerSessionEntry[];
56
61
  }>;
57
62
  }
58
- export declare function peerSessionsForUser(userId: string, sourceQueryId?: string): Promise<PeerSessionsResult>;
63
+ export declare function peerSessionsForUser(userId: string, sourceQueryId?: string, fromTopicId?: string): Promise<PeerSessionsResult>;
59
64
  export declare function deliverPeerReply(route: RemoteReplyRoute, sourceTitle: string, replyText: string, kind: "reply" | "error"): Promise<boolean>;
@@ -23,4 +23,6 @@ export declare function runTurnEventStream(topicId: string, topicTitle: string,
23
23
  silent?: boolean;
24
24
  peerBridge?: PeerRuntimeBridgeContext;
25
25
  sourceNode?: string;
26
+ /** Answer inside this thread instead of the room's main flow (S-13). */
27
+ threadRootId?: string;
26
28
  }): Promise<StreamAgentOutcome>;
@@ -30,6 +30,7 @@ export declare function streamAgentEvents(topicId: string, topicTitle: string, q
30
30
  silent?: boolean;
31
31
  peerBridge?: PeerRuntimeBridgeContext;
32
32
  sourceNode?: string;
33
+ threadRootId?: string;
33
34
  }): Promise<StreamAgentOutcome>;
34
35
  type AskPendingFileRef = {
35
36
  requestId?: string;
@@ -105,6 +106,8 @@ export interface AiTurnExecutionOptions {
105
106
  origin?: string;
106
107
  /** Origin node for transcript echo suppression. */
107
108
  sourceNode?: string;
109
+ /** Answer inside this thread instead of the room's main flow (S-13). */
110
+ threadRootId?: string;
108
111
  /** Fired when the turn is actually dispatched, including after a defer. */
109
112
  onDispatched?: (queryId: string) => void;
110
113
  /** Inter-session requestId for queue dedup (session-inject only). */
@@ -11,11 +11,33 @@ import type { AiMode, TopicDto, TopicKind, TopicSurface, TopicVisibility } from
11
11
  */
12
12
  export declare function defaultTopicSurface(): TopicSurface;
13
13
  export declare function normalizeTopicSurface(value: unknown): TopicSurface;
14
+ export declare function normalizeSurfaceScope(value: unknown): string | null;
15
+ export declare function defaultSurfaceScope(): string | null;
16
+ /** Install (or clear) the scope new rooms inherit. Returns the previous value. */
17
+ export declare function setDefaultSurfaceScope(scope: string | null): string | null;
18
+ export declare function setSurfaceScopeRequired(required: boolean): void;
19
+ export declare function isSurfaceScopeRequired(): boolean;
14
20
  /** Persist the authoritative agent and, when supplied, its normalized base defaults. */
15
21
  export declare function setApiTopicAgent(topicId: string, agent: AgentKind, defaults?: {
16
22
  model: string;
17
23
  effort?: EffortLevel;
18
24
  }): void;
25
+ /**
26
+ * M-9 — file every pre-existing Otium room under the workspace attached now.
27
+ *
28
+ * Deliberately *not* a schema-init step. The scope is only knowable after the
29
+ * first successful Central contact (M-3), which happens long after the store
30
+ * opens; a boot-time migration would see no scope, record itself as applied and
31
+ * leave every room unstamped forever. The Otium runtime calls this instead, once,
32
+ * as soon as it has resolved its workspace.
33
+ *
34
+ * Runs at most once per store: rooms created after this point are stamped at
35
+ * creation, and a second workspace joined later must not swallow the first
36
+ * one's rooms. Unlike the surface migration this can never rename anything —
37
+ * the scope enters the uniqueness key in the same release, so nothing can start
38
+ * colliding because of it.
39
+ */
40
+ export declare function stampUnscopedOtiumTopics(scope: string): number;
19
41
  export interface TopicRow {
20
42
  id: string;
21
43
  title: string;
@@ -35,6 +57,7 @@ export interface TopicRow {
35
57
  subagent_report_mode: string | null;
36
58
  visibility: string | null;
37
59
  surface: string | null;
60
+ surface_scope: string | null;
38
61
  browser_profile_owner: string | null;
39
62
  session_id: string | null;
40
63
  }
@@ -80,10 +103,22 @@ export declare function upsertTopic(t: TopicDto): void;
80
103
  */
81
104
  export declare function listTopics(opts?: {
82
105
  surface?: TopicSurface;
106
+ surfaceScope?: string | null;
83
107
  }): TopicDto[];
84
108
  export declare function getTopic(id: string): TopicDto | null;
85
109
  /** Return the private manager room owned by a user, excluding the retired shared General row. */
86
- export declare function getManagerTopicForUser(userId: string): TopicDto | null;
110
+ /**
111
+ * The user's own manager room, optionally on one surface.
112
+ *
113
+ * A manager room is one per user **per surface**: Terminal and Telegram each
114
+ * give the same person their own personal room, and returning one surface's
115
+ * room to the other adapter lets that adapter bind to — and reclassify — a room
116
+ * belonging to a different surface. Callers that represent an adapter pass
117
+ * theirs; unscoped lookups stay for maintenance paths that work by user alone.
118
+ */
119
+ export declare function getManagerTopicForUser(userId: string, surface?: TopicSurface, opts?: {
120
+ surfaceScope?: string | null;
121
+ }): TopicDto | null;
87
122
  /**
88
123
  * Resolve the topic whose wiki memory should be used for this topic.
89
124
  *
@@ -96,12 +131,15 @@ export declare function getTopicMemoryOrigin(id: string): TopicDto | null;
96
131
  export declare function getTopicByName(title: string): TopicDto | null;
97
132
  export declare function getTopicByNameAndKind(title: string, kind: TopicKind): TopicDto | null;
98
133
  /**
99
- * Titles are unique **per surface**, not per node: `otium` may exist once on
100
- * the terminal, once on telegram and once on the Otium hub.
134
+ * Titles are unique **per surface instance**, not per node: `otium` may exist
135
+ * once on the terminal, once on telegram, and once in *each* attached Otium
136
+ * workspace (M-1). Two workspaces are two namespaces that never see each other,
137
+ * so a name taken in one says nothing about the other.
101
138
  */
102
139
  export declare function findTopicTitleConflict(title: string, kind: TopicKind, opts?: {
103
140
  excludeTopicId?: string;
104
141
  surface?: TopicSurface;
142
+ surfaceScope?: string | null;
105
143
  }): TopicDto | null;
106
144
  /**
107
145
  * Move topics onto a surface. Used by adapters that own a classification the
@@ -112,6 +150,7 @@ export declare function setTopicSurfaces(topicIds: readonly string[], surface: T
112
150
  /** Look up a topic by title, restricted to topics where `userId` participates. */
113
151
  export declare function getTopicByNameForUser(title: string, userId: string, opts?: {
114
152
  surface?: TopicSurface;
153
+ surfaceScope?: string | null;
115
154
  }): TopicDto | null;
116
155
  /** Persist the agent session ID for a topic after a successful turn. */
117
156
  export declare function setTopicSessionId(topicId: string, sessionId: string, context?: TopicSessionLogContext): void;
@@ -29,6 +29,12 @@ export interface RuntimeUserTurnExecution {
29
29
  providerSessionId?: string;
30
30
  /** Request ids whose ordered messages were folded into this replacement. */
31
31
  supersededRequestIds?: string[];
32
+ /**
33
+ * Slack-style thread this turn belongs to, when it was asked in one. Carried
34
+ * on the request rather than the message because it decides both where the
35
+ * answer goes and which pending requests may merge with it (S-13).
36
+ */
37
+ threadRootId?: string;
32
38
  }
33
39
  export interface RuntimeUserTurnRequest {
34
40
  requestId: string;
@@ -47,6 +47,7 @@ export declare function recordUsage(userId: number | string, session: string, us
47
47
  agent: AgentKind;
48
48
  model: string;
49
49
  }): void;
50
+ export declare function deleteTopicStats(userId: number | string, topicId: string): void;
50
51
  export declare function getStats(userId: number | string, from?: string, to?: string): {
51
52
  total: Bucket;
52
53
  byHour: Record<string, Bucket>;
@@ -56,4 +57,4 @@ export declare function getStats(userId: number | string, from?: string, to?: st
56
57
  estimatedCostUsd: number;
57
58
  };
58
59
  /** Exact all-time usage for one topic, independent of transcript pagination. */
59
- export declare function getTopicStats(userId: number | string, topicId: string): TopicUsageSummary;
60
+ export declare function getTopicStats(userId: number | string, topicId: string, activeProviderSessionId?: string | undefined): TopicUsageSummary;
@@ -11,6 +11,7 @@ import type { AgentKind } from "../types";
11
11
  import type { TopicDto, TopicSurface } from "../types/api";
12
12
  export declare function getTopics(opts?: {
13
13
  surface?: TopicSurface;
14
+ surfaceScope?: string | null;
14
15
  }): TopicDto[];
15
16
  /**
16
17
  * Topics adapters may show in lists and selection UIs.
@@ -20,6 +21,7 @@ export declare function getTopics(opts?: {
20
21
  */
21
22
  export declare function getVisibleTopics(opts?: {
22
23
  surface?: TopicSurface;
24
+ surfaceScope?: string | null;
23
25
  }): TopicDto[];
24
26
  export declare function updateTopic(topicId: string, patch: Partial<TopicDto>): boolean;
25
27
  export declare function isParticipant(topic: TopicDto, userId: string): boolean;
@@ -1,4 +1,4 @@
1
- import type { TopicDto } from "../types/api";
1
+ import type { TopicDto, TopicSurface } from "../types/api";
2
2
  export declare const PERSONAL_GENERAL_DESCRIPTION = "Your private General. Messages and membership are visible only to you. Workspace memory, wiki, and skills are shared with your workspace.";
3
3
  /**
4
4
  * Return the caller's private General room, creating it on first use.
@@ -6,7 +6,9 @@ export declare const PERSONAL_GENERAL_DESCRIPTION = "Your private General. Messa
6
6
  * The legacy `general` row is deliberately excluded: it was shared by every
7
7
  * user and remains untouched for an explicit, operator-controlled migration.
8
8
  */
9
- export declare function ensurePersonalGeneral(userId: string): TopicDto;
9
+ export declare function ensurePersonalGeneral(userId: string, surface?: TopicSurface, opts?: {
10
+ surfaceScope?: string | null;
11
+ }): TopicDto;
10
12
  /** Resolve the retired fixed id for old clients without exposing the shared row. */
11
13
  export declare function resolvePersonalTopicId(topicId: string, userId: string): string;
12
14
  export declare function isManagerTopic(topicId: string): boolean;
@@ -121,6 +121,13 @@ export interface TopicDto {
121
121
  visibility?: TopicVisibility;
122
122
  /** The product surface that owns this topic (terminal / telegram / otium). */
123
123
  surface?: TopicSurface;
124
+ /**
125
+ * Which instance of the surface owns this topic — for `otium`, the workspace
126
+ * (M-1/M-2). Fixed at creation, exactly like `surface`. Null/absent on
127
+ * `terminal` and `telegram`, which have exactly one instance each, and on
128
+ * Otium rooms created before the scope was known.
129
+ */
130
+ surfaceScope?: string | null;
124
131
  /** Stable execution placement. Absent means the hub runs this topic locally. */
125
132
  executionNode?: {
126
133
  nodeId: string;
@@ -1 +1 @@
1
- export declare const NEGOTIUM_VERSION = "0.2.27";
1
+ export declare const NEGOTIUM_VERSION = "0.2.28";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "negotium",
3
- "version": "0.2.27",
3
+ "version": "0.2.28",
4
4
  "type": "module",
5
5
  "description": "Install the Negotium multi-agent runtime and CLI with one package",
6
6
  "license": "Apache-2.0",