@m6d/cortex-server 2.3.0 → 2.5.0

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 (62) hide show
  1. package/contracts/src/runtime/index.ts +99 -3
  2. package/dist/contracts/src/graph/helpers.d.ts +5 -5
  3. package/dist/contracts/src/runtime/index.d.ts +175 -3
  4. package/dist/src/lib/adapters/database/index.d.ts +20 -2
  5. package/dist/src/lib/adapters/database/mssql/attachments.d.ts +9 -9
  6. package/dist/src/lib/adapters/database/mssql/index.d.ts +133 -28
  7. package/dist/src/lib/adapters/database/mssql/llm-requests.d.ts +3 -2
  8. package/dist/src/lib/adapters/database/mssql/messages.d.ts +6 -5
  9. package/dist/src/lib/adapters/database/mssql/outbox.d.ts +103 -0
  10. package/dist/src/lib/adapters/database/mssql/threads.d.ts +21 -14
  11. package/dist/src/lib/adapters/database/postgres/attachments.d.ts +9 -9
  12. package/dist/src/lib/adapters/database/postgres/index.d.ts +133 -28
  13. package/dist/src/lib/adapters/database/postgres/llm-requests.d.ts +3 -2
  14. package/dist/src/lib/adapters/database/postgres/messages.d.ts +6 -5
  15. package/dist/src/lib/adapters/database/postgres/outbox.d.ts +103 -0
  16. package/dist/src/lib/adapters/database/postgres/threads.d.ts +21 -14
  17. package/dist/src/lib/ai/attachments.d.ts +2 -2
  18. package/dist/src/lib/ai/client-tools.d.ts +1 -1
  19. package/dist/src/lib/auth/middleware.d.ts +2 -2
  20. package/dist/src/lib/auth/playground.d.ts +14 -0
  21. package/dist/src/lib/cc/client.d.ts +9 -1
  22. package/dist/src/lib/cc/flusher.d.ts +40 -0
  23. package/dist/src/lib/cc/sync-events.d.ts +45 -0
  24. package/dist/src/lib/cc/types.d.ts +1 -1
  25. package/dist/src/lib/config.d.ts +11 -0
  26. package/dist/src/lib/db/schema.mssql.d.ts +161 -0
  27. package/dist/src/lib/db/schema.pg.d.ts +199 -0
  28. package/dist/src/lib/factory.d.ts +3 -0
  29. package/dist/src/lib/routes/owned-thread.d.ts +5 -4
  30. package/package.json +2 -2
  31. package/src/lib/adapters/database/index.ts +15 -1
  32. package/src/lib/adapters/database/mssql/index.ts +13 -4
  33. package/src/lib/adapters/database/mssql/llm-requests.ts +35 -15
  34. package/src/lib/adapters/database/mssql/messages.ts +81 -30
  35. package/src/lib/adapters/database/mssql/outbox.ts +71 -0
  36. package/src/lib/adapters/database/mssql/threads.ts +42 -11
  37. package/src/lib/adapters/database/postgres/index.ts +13 -4
  38. package/src/lib/adapters/database/postgres/llm-requests.ts +35 -15
  39. package/src/lib/adapters/database/postgres/messages.ts +81 -30
  40. package/src/lib/adapters/database/postgres/outbox.ts +66 -0
  41. package/src/lib/adapters/database/postgres/threads.ts +39 -11
  42. package/src/lib/ai/finish-turn.ts +3 -1
  43. package/src/lib/ai/prompt.ts +3 -1
  44. package/src/lib/auth/middleware.ts +34 -8
  45. package/src/lib/auth/playground.ts +72 -0
  46. package/src/lib/cc/client.ts +21 -1
  47. package/src/lib/cc/flusher.ts +147 -0
  48. package/src/lib/cc/sync-events.ts +65 -0
  49. package/src/lib/cc/types.ts +3 -0
  50. package/src/lib/config.ts +11 -0
  51. package/src/lib/db/migrations/mssql/20260829050547_friendly_red_shift/migration.sql +8 -0
  52. package/src/lib/db/migrations/mssql/20260829050547_friendly_red_shift/snapshot.json +581 -0
  53. package/src/lib/db/migrations/mssql/20260830022424_easy_nicolaos/migration.sql +5 -0
  54. package/src/lib/db/migrations/mssql/20260830022424_easy_nicolaos/snapshot.json +614 -0
  55. package/src/lib/db/migrations/pg/20260829050547_perfect_wildside/migration.sql +7 -0
  56. package/src/lib/db/migrations/pg/20260829050547_perfect_wildside/snapshot.json +650 -0
  57. package/src/lib/db/migrations/pg/20260830022424_serious_deadpool/migration.sql +4 -0
  58. package/src/lib/db/migrations/pg/20260830022424_serious_deadpool/snapshot.json +690 -0
  59. package/src/lib/db/schema.mssql.ts +32 -1
  60. package/src/lib/db/schema.pg.ts +24 -0
  61. package/src/lib/factory.ts +22 -8
  62. package/src/lib/routes/threads.ts +5 -1
@@ -4,7 +4,9 @@ import type { StorageAdapter } from "../../../adapters/storage/index";
4
4
  * table; only threads takes storage, because deleting a thread is the one
5
5
  * operation that also has to reach into object storage.
6
6
  */
7
- export declare function createPostgresAdapter(connectionString: string, storage?: StorageAdapter): {
7
+ export declare function createPostgresAdapter(connectionString: string, storage?: StorageAdapter, options?: {
8
+ syncMirror?: boolean;
9
+ }): {
8
10
  threads: {
9
11
  list(userId: string, agentId: string): Promise<{
10
12
  createdAt: Date;
@@ -13,39 +15,45 @@ export declare function createPostgresAdapter(connectionString: string, storage?
13
15
  userId: string;
14
16
  agentId: string;
15
17
  title: string | null;
18
+ isTest: boolean;
16
19
  session: Record<string, unknown> | null;
17
20
  contextMeta: import("../../..").ThreadContextMeta | null;
18
21
  }[]>;
19
22
  getById(userId: string, threadId: string): Promise<{
20
- id: string;
21
- userId: string;
22
23
  agentId: string;
24
+ userId: string;
25
+ id: string;
23
26
  title: string | null;
24
- session: Record<string, unknown> | null;
25
- contextMeta: import("../../..").ThreadContextMeta | null;
27
+ isTest: boolean;
26
28
  createdAt: Date;
27
29
  updatedAt: Date;
30
+ session: Record<string, unknown> | null;
31
+ contextMeta: import("../../..").ThreadContextMeta | null;
28
32
  } | null>;
29
- create(userId: string, agentId: string): Promise<{
30
- id: string;
31
- userId: string;
33
+ create(userId: string, agentId: string, options: {
34
+ isTest?: boolean;
35
+ } | undefined): Promise<{
32
36
  agentId: string;
37
+ userId: string;
38
+ id: string;
33
39
  title: string | null;
34
- session: Record<string, unknown> | null;
35
- contextMeta: import("../../..").ThreadContextMeta | null;
40
+ isTest: boolean;
36
41
  createdAt: Date;
37
42
  updatedAt: Date;
43
+ session: Record<string, unknown> | null;
44
+ contextMeta: import("../../..").ThreadContextMeta | null;
38
45
  }>;
39
46
  delete(userId: string, threadId: string): Promise<void>;
40
47
  touch(threadId: string): Promise<{
41
- id: string;
42
- userId: string;
43
48
  agentId: string;
49
+ userId: string;
50
+ id: string;
44
51
  title: string | null;
45
- session: Record<string, unknown> | null;
46
- contextMeta: import("../../..").ThreadContextMeta | null;
52
+ isTest: boolean;
47
53
  createdAt: Date;
48
54
  updatedAt: Date;
55
+ session: Record<string, unknown> | null;
56
+ contextMeta: import("../../..").ThreadContextMeta | null;
49
57
  }>;
50
58
  updateTitle(threadId: string, title: string): Promise<void>;
51
59
  updateSession(threadId: string, session: Record<string, unknown>): Promise<void>;
@@ -55,14 +63,14 @@ export declare function createPostgresAdapter(connectionString: string, storage?
55
63
  list(userId: string, threadId: string, opts: {
56
64
  limit?: number;
57
65
  } | undefined): Promise<{
58
- id: string;
59
66
  text: string | null;
67
+ threadId: string;
68
+ id: string;
60
69
  createdAt: Date;
61
70
  updatedAt: Date;
62
- threadId: string;
63
- content: import("../../../types").ChatMessage;
64
- ordinal: number;
65
71
  role: "system" | "user" | "assistant" | "tool";
72
+ ordinal: number;
73
+ content: import("../../../types").ChatMessage;
66
74
  }[] | {
67
75
  createdAt: Date;
68
76
  updatedAt: Date;
@@ -78,7 +86,7 @@ export declare function createPostgresAdapter(connectionString: string, storage?
78
86
  }): Promise<void>;
79
87
  };
80
88
  llmRequests: {
81
- insert(requests: {
89
+ insert(threadId: string, requests: {
82
90
  messageId: string;
83
91
  stepNumber: number;
84
92
  prompt: string;
@@ -94,8 +102,8 @@ export declare function createPostgresAdapter(connectionString: string, storage?
94
102
  };
95
103
  attachments: {
96
104
  createPending(row: {
97
- userId: string;
98
105
  threadId: string;
106
+ userId: string;
99
107
  filename: string;
100
108
  contentType: string;
101
109
  sizeBytes: number;
@@ -107,11 +115,11 @@ export declare function createPostgresAdapter(connectionString: string, storage?
107
115
  messageId?: string | null | undefined;
108
116
  description?: string | null | undefined;
109
117
  }, limit: number): Promise<{
110
- id: string;
118
+ threadId: string;
111
119
  userId: string;
120
+ id: string;
112
121
  createdAt: Date;
113
122
  updatedAt: Date;
114
- threadId: string;
115
123
  messageId: string | null;
116
124
  filename: string;
117
125
  contentType: string;
@@ -121,11 +129,11 @@ export declare function createPostgresAdapter(connectionString: string, storage?
121
129
  description: string | null;
122
130
  } | undefined>;
123
131
  getById(id: string, userId: string): Promise<{
124
- id: string;
132
+ threadId: string;
125
133
  userId: string;
134
+ id: string;
126
135
  createdAt: Date;
127
136
  updatedAt: Date;
128
- threadId: string;
129
137
  messageId: string | null;
130
138
  filename: string;
131
139
  contentType: string;
@@ -177,11 +185,11 @@ export declare function createPostgresAdapter(connectionString: string, storage?
177
185
  }[]>;
178
186
  setDescription(id: string, userId: string, status: "pending" | "described" | "failed" | "skipped", description: string | undefined): Promise<void>;
179
187
  remove(id: string, userId: string): Promise<{
180
- id: string;
188
+ threadId: string;
181
189
  userId: string;
190
+ id: string;
182
191
  createdAt: Date;
183
192
  updatedAt: Date;
184
- threadId: string;
185
193
  messageId: string | null;
186
194
  filename: string;
187
195
  contentType: string;
@@ -190,11 +198,11 @@ export declare function createPostgresAdapter(connectionString: string, storage?
190
198
  status: "pending" | "described" | "failed" | "skipped";
191
199
  description: string | null;
192
200
  } | {
193
- id: string;
201
+ threadId: string;
194
202
  userId: string;
203
+ id: string;
195
204
  createdAt: Date;
196
205
  updatedAt: Date;
197
- threadId: string;
198
206
  messageId: string | null;
199
207
  filename: string;
200
208
  contentType: string;
@@ -204,4 +212,101 @@ export declare function createPostgresAdapter(connectionString: string, storage?
204
212
  description: string | null;
205
213
  } | undefined>;
206
214
  };
215
+ outbox: {
216
+ enqueue: (events: ({
217
+ type: "thread.upsert";
218
+ id: string;
219
+ agentSlug: string;
220
+ userId: string;
221
+ title: string | null;
222
+ isTest: boolean;
223
+ createdAt: string;
224
+ updatedAt: string;
225
+ } | {
226
+ type: "thread.delete";
227
+ id: string;
228
+ } | {
229
+ type: "message.upsert";
230
+ id: string;
231
+ threadId: string;
232
+ role: "system" | "user" | "assistant" | "tool";
233
+ text: string | null;
234
+ ordinal: number;
235
+ content: {
236
+ [x: string]: unknown;
237
+ };
238
+ createdAt: string;
239
+ } | {
240
+ type: "usage.record";
241
+ id: string;
242
+ messageId: string;
243
+ threadId: string;
244
+ stepNumber: number;
245
+ tokenUsage: {
246
+ input: {
247
+ noCache: number;
248
+ cacheRead: number;
249
+ cacheWrite: number;
250
+ total: number;
251
+ };
252
+ output: {
253
+ reasoning: number;
254
+ text: number;
255
+ total: number;
256
+ };
257
+ total: number;
258
+ };
259
+ createdAt: string;
260
+ })[]) => Promise<void>;
261
+ peek(limit: number): Promise<{
262
+ id: number;
263
+ event: {
264
+ type: "thread.upsert";
265
+ id: string;
266
+ agentSlug: string;
267
+ userId: string;
268
+ title: string | null;
269
+ isTest: boolean;
270
+ createdAt: string;
271
+ updatedAt: string;
272
+ } | {
273
+ type: "thread.delete";
274
+ id: string;
275
+ } | {
276
+ type: "message.upsert";
277
+ id: string;
278
+ threadId: string;
279
+ role: "system" | "user" | "assistant" | "tool";
280
+ text: string | null;
281
+ ordinal: number;
282
+ content: {
283
+ [x: string]: unknown;
284
+ };
285
+ createdAt: string;
286
+ } | {
287
+ type: "usage.record";
288
+ id: string;
289
+ messageId: string;
290
+ threadId: string;
291
+ stepNumber: number;
292
+ tokenUsage: {
293
+ input: {
294
+ noCache: number;
295
+ cacheRead: number;
296
+ cacheWrite: number;
297
+ total: number;
298
+ };
299
+ output: {
300
+ reasoning: number;
301
+ text: number;
302
+ total: number;
303
+ };
304
+ total: number;
305
+ };
306
+ createdAt: string;
307
+ };
308
+ }[]>;
309
+ epoch(): Promise<string>;
310
+ ack(ids: number[]): Promise<void>;
311
+ };
207
312
  };
@@ -1,6 +1,7 @@
1
1
  import type { PostgresDb } from "./client";
2
- export declare function createLlmRequestsRepository(db: PostgresDb): {
3
- insert(requests: {
2
+ import { enqueueSyncEvents } from "./outbox";
3
+ export declare function createLlmRequestsRepository(db: PostgresDb, enqueue?: typeof enqueueSyncEvents): {
4
+ insert(threadId: string, requests: {
4
5
  messageId: string;
5
6
  stepNumber: number;
6
7
  prompt: string;
@@ -1,6 +1,7 @@
1
1
  import type { ChatMessage } from "../../../types";
2
2
  import type { PostgresDb } from "./client";
3
- export declare function createMessagesRepository(db: PostgresDb): {
3
+ import { enqueueSyncEvents } from "./outbox";
4
+ export declare function createMessagesRepository(db: PostgresDb, enqueue?: typeof enqueueSyncEvents): {
4
5
  /**
5
6
  * Fetches the newest N and reverses, so a limit keeps the most recent
6
7
  * messages while callers still receive them oldest-first.
@@ -8,14 +9,14 @@ export declare function createMessagesRepository(db: PostgresDb): {
8
9
  list(userId: string, threadId: string, opts: {
9
10
  limit?: number;
10
11
  } | undefined): Promise<{
11
- id: string;
12
12
  text: string | null;
13
+ threadId: string;
14
+ id: string;
13
15
  createdAt: Date;
14
16
  updatedAt: Date;
15
- threadId: string;
16
- content: ChatMessage;
17
- ordinal: number;
18
17
  role: "system" | "user" | "assistant" | "tool";
18
+ ordinal: number;
19
+ content: ChatMessage;
19
20
  }[] | {
20
21
  createdAt: Date;
21
22
  updatedAt: Date;
@@ -0,0 +1,103 @@
1
+ import type { SyncEvent } from "../../../../../contracts/src/runtime";
2
+ import type { PostgresDb } from "./client";
3
+ /** A db or one of its transactions, so a write and its events commit together. */
4
+ type Executor = Pick<PostgresDb, "insert">;
5
+ export declare function enqueueSyncEvents(executor: Executor, events: SyncEvent[]): Promise<void>;
6
+ export declare function createOutboxRepository(db: PostgresDb): {
7
+ enqueue: (events: ({
8
+ type: "thread.upsert";
9
+ id: string;
10
+ agentSlug: string;
11
+ userId: string;
12
+ title: string | null;
13
+ isTest: boolean;
14
+ createdAt: string;
15
+ updatedAt: string;
16
+ } | {
17
+ type: "thread.delete";
18
+ id: string;
19
+ } | {
20
+ type: "message.upsert";
21
+ id: string;
22
+ threadId: string;
23
+ role: "system" | "user" | "assistant" | "tool";
24
+ text: string | null;
25
+ ordinal: number;
26
+ content: {
27
+ [x: string]: unknown;
28
+ };
29
+ createdAt: string;
30
+ } | {
31
+ type: "usage.record";
32
+ id: string;
33
+ messageId: string;
34
+ threadId: string;
35
+ stepNumber: number;
36
+ tokenUsage: {
37
+ input: {
38
+ noCache: number;
39
+ cacheRead: number;
40
+ cacheWrite: number;
41
+ total: number;
42
+ };
43
+ output: {
44
+ reasoning: number;
45
+ text: number;
46
+ total: number;
47
+ };
48
+ total: number;
49
+ };
50
+ createdAt: string;
51
+ })[]) => Promise<void>;
52
+ peek(limit: number): Promise<{
53
+ id: number;
54
+ event: {
55
+ type: "thread.upsert";
56
+ id: string;
57
+ agentSlug: string;
58
+ userId: string;
59
+ title: string | null;
60
+ isTest: boolean;
61
+ createdAt: string;
62
+ updatedAt: string;
63
+ } | {
64
+ type: "thread.delete";
65
+ id: string;
66
+ } | {
67
+ type: "message.upsert";
68
+ id: string;
69
+ threadId: string;
70
+ role: "system" | "user" | "assistant" | "tool";
71
+ text: string | null;
72
+ ordinal: number;
73
+ content: {
74
+ [x: string]: unknown;
75
+ };
76
+ createdAt: string;
77
+ } | {
78
+ type: "usage.record";
79
+ id: string;
80
+ messageId: string;
81
+ threadId: string;
82
+ stepNumber: number;
83
+ tokenUsage: {
84
+ input: {
85
+ noCache: number;
86
+ cacheRead: number;
87
+ cacheWrite: number;
88
+ total: number;
89
+ };
90
+ output: {
91
+ reasoning: number;
92
+ text: number;
93
+ total: number;
94
+ };
95
+ total: number;
96
+ };
97
+ createdAt: string;
98
+ };
99
+ }[]>;
100
+ epoch(): Promise<string>;
101
+ ack(ids: number[]): Promise<void>;
102
+ };
103
+ export {};
@@ -1,7 +1,8 @@
1
1
  import type { ThreadContextMeta } from "../../../ai/context/types";
2
2
  import type { PostgresDb } from "./client";
3
+ import { enqueueSyncEvents } from "./outbox";
3
4
  import type { StorageAdapter } from "../../../adapters/storage/index";
4
- export declare function createThreadsRepository(db: PostgresDb, storage?: StorageAdapter): {
5
+ export declare function createThreadsRepository(db: PostgresDb, storage?: StorageAdapter, enqueue?: typeof enqueueSyncEvents): {
5
6
  list(userId: string, agentId: string): Promise<{
6
7
  createdAt: Date;
7
8
  updatedAt: Date;
@@ -9,40 +10,46 @@ export declare function createThreadsRepository(db: PostgresDb, storage?: Storag
9
10
  userId: string;
10
11
  agentId: string;
11
12
  title: string | null;
13
+ isTest: boolean;
12
14
  session: Record<string, unknown> | null;
13
15
  contextMeta: ThreadContextMeta | null;
14
16
  }[]>;
15
17
  getById(userId: string, threadId: string): Promise<{
16
- id: string;
17
- userId: string;
18
18
  agentId: string;
19
+ userId: string;
20
+ id: string;
19
21
  title: string | null;
20
- session: Record<string, unknown> | null;
21
- contextMeta: ThreadContextMeta | null;
22
+ isTest: boolean;
22
23
  createdAt: Date;
23
24
  updatedAt: Date;
25
+ session: Record<string, unknown> | null;
26
+ contextMeta: ThreadContextMeta | null;
24
27
  } | null>;
25
- create(userId: string, agentId: string): Promise<{
26
- id: string;
27
- userId: string;
28
+ create(userId: string, agentId: string, options: {
29
+ isTest?: boolean;
30
+ } | undefined): Promise<{
28
31
  agentId: string;
32
+ userId: string;
33
+ id: string;
29
34
  title: string | null;
30
- session: Record<string, unknown> | null;
31
- contextMeta: ThreadContextMeta | null;
35
+ isTest: boolean;
32
36
  createdAt: Date;
33
37
  updatedAt: Date;
38
+ session: Record<string, unknown> | null;
39
+ contextMeta: ThreadContextMeta | null;
34
40
  }>;
35
41
  /** Object storage has no foreign keys, so attachment paths must be swept before row cascade. */
36
42
  delete(userId: string, threadId: string): Promise<void>;
37
43
  touch(threadId: string): Promise<{
38
- id: string;
39
- userId: string;
40
44
  agentId: string;
45
+ userId: string;
46
+ id: string;
41
47
  title: string | null;
42
- session: Record<string, unknown> | null;
43
- contextMeta: ThreadContextMeta | null;
48
+ isTest: boolean;
44
49
  createdAt: Date;
45
50
  updatedAt: Date;
51
+ session: Record<string, unknown> | null;
52
+ contextMeta: ThreadContextMeta | null;
46
53
  }>;
47
54
  updateTitle(threadId: string, title: string): Promise<void>;
48
55
  updateSession(threadId: string, session: Record<string, unknown>): Promise<void>;
@@ -12,11 +12,11 @@ type AttachmentCapabilities = {
12
12
  attachmentSentinels: boolean;
13
13
  };
14
14
  export declare function prepareAttachmentsForTurn(options: PrepareAttachmentsOptions): Promise<{
15
- id: string;
15
+ threadId: string;
16
16
  userId: string;
17
+ id: string;
17
18
  createdAt: Date;
18
19
  updatedAt: Date;
19
- threadId: string;
20
20
  messageId: string | null;
21
21
  filename: string;
22
22
  contentType: string;
@@ -30,7 +30,7 @@ export declare function createCcClient(config: ResolvedCortexAgentConfig): Contr
30
30
  export declare function clientToolAnswersFrom(forwardedProps: Record<string, unknown>): {
31
31
  toolCallId: string;
32
32
  output: unknown;
33
- state: "complete" | "error";
33
+ state: "error" | "complete";
34
34
  }[] | null;
35
35
  /**
36
36
  * Applies client tool answers to the stored messages carrying their calls,
@@ -1,4 +1,4 @@
1
1
  import type { AppEnv, AuthedAppEnv } from "../types";
2
- import type { CortexConfig } from "../config";
3
- export declare function createUserLoaderMiddleware(authConfig: CortexConfig["auth"]): import("hono").MiddlewareHandler<AppEnv, string, {}, Response>;
2
+ import type { ControlCenterConfig, CortexConfig } from "../config";
3
+ export declare function createUserLoaderMiddleware(authConfig: CortexConfig["auth"], controlCenter?: ControlCenterConfig): import("hono").MiddlewareHandler<AppEnv, string, {}, Response>;
4
4
  export declare const requireAuth: import("hono").MiddlewareHandler<AuthedAppEnv, string, {}, Response>;
@@ -0,0 +1,14 @@
1
+ import type { ControlCenterConfig } from "../config";
2
+ export declare function ccIssuer(config: ControlCenterConfig): string;
3
+ /**
4
+ * True when the token's (unverified) `iss` names the playground-enabled cc —
5
+ * the routing decision only; verification still happens against the JWKS.
6
+ */
7
+ export declare function isPlaygroundToken(controlCenter: ControlCenterConfig | undefined, token: string): boolean;
8
+ export declare function verifyPlaygroundToken(controlCenter: ControlCenterConfig, token: string): Promise<import("jose").JWTPayload>;
9
+ /**
10
+ * Verifies the cc-signed `X-Cortex-Playground` header. Works for both
11
+ * cc-minted and pasted-real-user-token modes: the header always carries the
12
+ * caller's own cc JWT, independent of the Authorization token.
13
+ */
14
+ export declare function isPlaygroundRequest(controlCenter: ControlCenterConfig | undefined, request: Request): Promise<boolean>;
@@ -1,5 +1,5 @@
1
1
  import type { ControlCenterConfig } from "../config";
2
- import type { ExecuteRequest, ResolveRequest, SearchRequest } from "./types";
2
+ import type { ExecuteRequest, ResolveRequest, SearchRequest, SyncRequest } from "./types";
3
3
  type ControlCenterFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
4
4
  export type ExecuteOptions = {
5
5
  readOnly: boolean;
@@ -191,6 +191,14 @@ export declare class ControlCenterClient {
191
191
  }[];
192
192
  };
193
193
  } | null>;
194
+ /**
195
+ * Pushes one outbox batch to `POST /api/runtime/sync` (server-level, not
196
+ * under an agent). Returns true — the flusher's license to delete the
197
+ * rows — only when cc itself confirms the whole batch: a 2xx whose body
198
+ * parses as the sync response and counts every event. A gateway serving
199
+ * HTML with a 200, or a partial count, keeps the rows queued for retry.
200
+ */
201
+ sync(request: SyncRequest, abortSignal?: AbortSignal): Promise<boolean>;
194
202
  private agentPath;
195
203
  private post;
196
204
  private postResponse;
@@ -0,0 +1,40 @@
1
+ import type { Redis } from "ioredis";
2
+ import type { DatabaseAdapter } from "../adapters/database/index";
3
+ import type { ControlCenterClient } from "./client";
4
+ /**
5
+ * Drains the sync outbox to cc every 10s: peek → sync → ack on success, rows
6
+ * stay put on failure so the next tick retries. A quiet outbox still POSTs an
7
+ * empty batch once a minute — that is the heartbeat behind cc's online badge.
8
+ *
9
+ * With Redis configured (multi-replica deployments), a per-tick lease keeps
10
+ * exactly one replica flushing at a time, so batches cannot overlap or land
11
+ * out of order. Without Redis the deployment is single-process and the
12
+ * in-flight flag alone suffices.
13
+ */
14
+ type OutboxRow = Awaited<ReturnType<DatabaseAdapter["outbox"]["peek"]>>[number];
15
+ type SyncEvent = OutboxRow["event"];
16
+ /** A contract-valid stand-in for a message too large for cc's request cap:
17
+ * enough text for the transcript, `content` reduced to a truncation marker.
18
+ * The full message stays in the server database. Only messages can grow
19
+ * unbounded; anything else oversized has no meaningful reduction. */
20
+ export declare function shrinkOversizedEvent(event: SyncEvent): {
21
+ text: string | null;
22
+ content: {
23
+ truncated: boolean;
24
+ };
25
+ type: "message.upsert";
26
+ id: string;
27
+ threadId: string;
28
+ role: "system" | "user" | "assistant" | "tool";
29
+ ordinal: number;
30
+ createdAt: string;
31
+ } | null;
32
+ /** Longest row prefix whose serialized events stay under cc's request body
33
+ * cap, or null when the head row alone can never fit (a poison pill that
34
+ * would wedge the queue if kept). */
35
+ export declare function sliceBatch(rows: OutboxRow[], maxBytes?: number): {
36
+ id: number;
37
+ event: import("./types").SyncEvent;
38
+ }[] | null;
39
+ export declare function startSyncFlusher(db: DatabaseAdapter, client: ControlCenterClient, redis?: Redis): () => void;
40
+ export {};
@@ -0,0 +1,45 @@
1
+ import type { ChatMessage, Thread, TokenUsage } from "../types";
2
+ export declare function threadUpsertEvent(thread: Thread): {
3
+ type: "thread.upsert";
4
+ id: string;
5
+ agentSlug: string;
6
+ userId: string;
7
+ title: string | null;
8
+ isTest: boolean;
9
+ createdAt: string;
10
+ updatedAt: string;
11
+ };
12
+ export declare function threadDeleteEvent(threadId: string): {
13
+ type: "thread.delete";
14
+ id: string;
15
+ };
16
+ export declare function messageUpsertEvent(input: {
17
+ threadId: string;
18
+ message: ChatMessage;
19
+ text: string | null | undefined;
20
+ ordinal: number;
21
+ createdAt: Date;
22
+ }): {
23
+ type: "message.upsert";
24
+ id: string;
25
+ threadId: string;
26
+ role: "system" | "user" | "assistant";
27
+ text: string | null;
28
+ ordinal: number;
29
+ content: Record<string, unknown>;
30
+ createdAt: string;
31
+ };
32
+ export declare function usageRecordEvent(input: {
33
+ threadId: string;
34
+ messageId: string;
35
+ stepNumber: number;
36
+ tokenUsage: TokenUsage;
37
+ }): {
38
+ type: "usage.record";
39
+ id: `${string}-${string}-${string}-${string}-${string}`;
40
+ messageId: string;
41
+ threadId: string;
42
+ stepNumber: number;
43
+ tokenUsage: TokenUsage;
44
+ createdAt: string;
45
+ };
@@ -1,5 +1,5 @@
1
1
  import z from "zod";
2
- export { AGENT_SLUG_PATTERN, executeResponseSchema, resolveResponseSchema, runtimeAgentConfigSchema, searchKnowledgeResponseSchema, searchServicesResponseSchema, searchToolsResponseSchema, type ExecuteRequest, type ResolveRequest, type ResolveResponse, type RuntimeAgentConfig, type SearchRequest, type ToolEmbed, } from "../../../contracts/src/runtime";
2
+ export { AGENT_SLUG_PATTERN, executeResponseSchema, resolveResponseSchema, runtimeAgentConfigSchema, searchKnowledgeResponseSchema, searchServicesResponseSchema, searchToolsResponseSchema, syncResponseSchema, type ExecuteRequest, type ResolveRequest, type ResolveResponse, type RuntimeAgentConfig, type SearchRequest, type SyncEvent, type SyncRequest, type ToolEmbed, } from "../../../contracts/src/runtime";
3
3
  /**
4
4
  * The contract's error envelope, hardened for this consumer: a newer runtime may
5
5
  * answer with an error kind this build has never heard of, which must degrade to a
@@ -36,6 +36,17 @@ type RerankerConfig = {
36
36
  export type ControlCenterConfig = {
37
37
  url: string;
38
38
  apiKey: string;
39
+ /**
40
+ * Trust cc as a secondary token issuer (its playground). cc-minted
41
+ * end-user JWTs then authenticate against `{url}/api/auth/jwks`, and a
42
+ * cc-signed `X-Cortex-Playground` header marks new threads as test data.
43
+ */
44
+ playground?: boolean;
45
+ /**
46
+ * The `iss` claim cc stamps (its Better Auth `baseURL`), when it differs
47
+ * from the URL this server dials. Defaults to `url`.
48
+ */
49
+ playgroundIssuer?: string;
39
50
  };
40
51
  export type KnowledgeConfig = {
41
52
  swagger?: {