@opengeni/db 5.0.1 → 6.0.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.
- package/dist/automations.d.ts +0 -2
- package/dist/canonical-human-identities.d.ts +4 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-components.d.ts +5 -13
- package/dist/capability-integrations.d.ts +23 -8
- package/dist/capability-reconciliation.d.ts +5 -0
- package/dist/capability-reconciliation.js +21 -0
- package/dist/capability-reconciliation.js.map +1 -0
- package/dist/{chunk-6T2GGYWE.js → chunk-4UJCXBR2.js} +4 -5800
- package/dist/chunk-4UJCXBR2.js.map +1 -0
- package/dist/{chunk-MWMXWHJD.js → chunk-7JCDSMX2.js} +2 -2
- package/dist/chunk-AJA2ZIUW.js +219 -0
- package/dist/chunk-AJA2ZIUW.js.map +1 -0
- package/dist/chunk-CDAT6EKW.js +247 -0
- package/dist/chunk-CDAT6EKW.js.map +1 -0
- package/dist/{chunk-DPONPYJD.js → chunk-CJI6G254.js} +70 -18
- package/dist/chunk-CJI6G254.js.map +1 -0
- package/dist/chunk-G32NVMRJ.js +276 -0
- package/dist/chunk-G32NVMRJ.js.map +1 -0
- package/dist/chunk-GABXCG3N.js +5811 -0
- package/dist/chunk-GABXCG3N.js.map +1 -0
- package/dist/{chunk-ERKVSPDX.js → chunk-LVY33EWL.js} +3 -3
- package/dist/{chunk-45CP2YKY.js → chunk-MAMBI2HR.js} +9 -3
- package/dist/{chunk-45CP2YKY.js.map → chunk-MAMBI2HR.js.map} +1 -1
- package/dist/{chunk-F73UKJY6.js → chunk-MN5PZMEK.js} +91 -108
- package/dist/chunk-MN5PZMEK.js.map +1 -0
- package/dist/chunk-PJI4MUZ7.js +131 -0
- package/dist/chunk-PJI4MUZ7.js.map +1 -0
- package/dist/{chunk-T6BWIGWJ.js → chunk-RIYHP2WU.js} +2 -2
- package/dist/{chunk-7HMK3B45.js → chunk-RL2MUXM3.js} +16 -7
- package/dist/chunk-RL2MUXM3.js.map +1 -0
- package/dist/{chunk-HQDVI2DB.js → chunk-SYKHLPTK.js} +4 -3
- package/dist/{chunk-HQDVI2DB.js.map → chunk-SYKHLPTK.js.map} +1 -1
- package/dist/{chunk-T6YLHJLS.js → chunk-XIXVVBW2.js} +198 -51
- package/dist/chunk-XIXVVBW2.js.map +1 -0
- package/dist/chunk-ZPJ6V2VG.js +156 -0
- package/dist/chunk-ZPJ6V2VG.js.map +1 -0
- package/dist/codex-capacity-recovery.d.ts +12 -0
- package/dist/codex-failure-eligibility.d.ts +9 -0
- package/dist/company-profile-schema.d.ts +4 -2
- package/dist/connect-attempts.d.ts +15 -0
- package/dist/connect-attempts.js +25 -0
- package/dist/connect-attempts.js.map +1 -0
- package/dist/connection-authority.d.ts +7 -63
- package/dist/connection-refresh-lock.d.ts +4 -0
- package/dist/connection-token-resolver.d.ts +8 -43
- package/dist/database-timing.d.ts +10 -0
- package/dist/database.d.ts +4 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.d.ts +9 -0
- package/dist/editable-artifacts.js +7 -5
- package/dist/index.d.ts +447 -78
- package/dist/index.js +12705 -12872
- package/dist/index.js.map +1 -1
- package/dist/insights-usage-bundle.d.ts +3 -0
- package/dist/integration-bindings.d.ts +1 -1
- package/dist/integration-facets.d.ts +18 -1
- package/dist/knowledge-entries-schema.d.ts +2 -0
- package/dist/knowledge-entries.d.ts +1 -0
- package/dist/knowledge-indexing.d.ts +1 -0
- package/dist/live-session-attempt.d.ts +35 -137
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/mcp-account-bindings.d.ts +4 -0
- package/dist/mcp-oauth.d.ts +11 -0
- package/dist/mcp-operations.js +2 -2
- package/dist/migrate.js +1 -1
- package/dist/organization-integration-policy.d.ts +51 -0
- package/dist/organization-integration-policy.js +18 -0
- package/dist/organization-integration-policy.js.map +1 -0
- package/dist/organization-usage.d.ts +20 -0
- package/dist/plugin-packages.d.ts +9 -12
- package/dist/pr-review.d.ts +0 -11
- package/dist/preference-registry-schema.d.ts +17 -0
- package/dist/provision-roles.js +1 -1
- package/dist/retained-provider-commands.d.ts +124 -6
- package/dist/retained-provider-commands.js +29 -97
- package/dist/retained-provider-commands.js.map +1 -1
- package/dist/retired-session-create-metadata.d.ts +4 -0
- package/dist/runtime-posture.d.ts +7 -5
- package/dist/schema.d.ts +876 -656
- package/dist/schema.js +5 -7
- package/dist/session-admission-block.d.ts +32 -0
- package/dist/session-attempt-writers.d.ts +4 -0
- package/dist/session-background-commands.js +5 -4
- package/dist/session-command-output.js +8 -126
- package/dist/session-command-output.js.map +1 -1
- package/dist/session-control.d.ts +5 -1
- package/dist/session-event-slices.d.ts +10 -0
- package/dist/session-event-slices.js +8 -222
- package/dist/session-event-slices.js.map +1 -1
- package/dist/session-file-attachments.d.ts +28 -0
- package/dist/session-goal-reports.d.ts +43 -0
- package/dist/session-mcp-approval.d.ts +4 -0
- package/dist/session-mcp-credential-rotation.js +5 -4
- package/dist/session-mcp-credential-rotation.js.map +1 -1
- package/dist/session-message-search.d.ts +22 -0
- package/dist/session-queue-commands.d.ts +2 -6
- package/dist/session-retry.d.ts +36 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/skill-source-release-impact.d.ts +18 -0
- package/dist/skill-source-release.d.ts +9 -0
- package/dist/skills.d.ts +7 -1
- package/dist/user-resource-authority.d.ts +0 -8
- package/dist/video-generation.js +3 -3
- package/dist/workspace-tool-defaults.js +5 -4
- package/dist/workspace-tool-defaults.js.map +1 -1
- package/drizzle/0468_knowledge_relationship_projection.sql +30 -0
- package/drizzle/0469_knowledge_source_discovery.sql +85 -0
- package/drizzle/0470_organization_integration_policy.sql +151 -0
- package/drizzle/0471_usage_events_account_recent_index.sql +4 -0
- package/drizzle/0472_usage_events_workspace_recent_index.sql +4 -0
- package/drizzle/0473_organization_usage_analytical_capability.sql +237 -0
- package/drizzle/0474_goal_report_requirements.sql +156 -0
- package/drizzle/0475_session_event_history_statistics.sql +15 -0
- package/drizzle/0476_session_event_history_policy_planning.sql +29 -0
- package/drizzle/0477_managed_sign_in_methods.sql +303 -0
- package/drizzle/0478_sender_owned_connections.sql +2772 -0
- package/drizzle/0479_connection_create_idempotency.sql +16 -0
- package/drizzle/0480_private_session_organization_key_administration.sql +154 -0
- package/drizzle/0481_personal_connection_visibility_cleanup.sql +45 -0
- package/drizzle/0482_remove_packs.sql +417 -0
- package/drizzle/0483_preclaim_admission_block.sql +85 -0
- package/drizzle/0484_insights_usage_projection.sql +211 -0
- package/drizzle/0485_inherited_mcp_approval_policies.sql +6 -0
- package/drizzle/0486_reasoning_configuration_message_forks.sql +35 -0
- package/drizzle/0487_skill_catalog_message_forks.sql +26 -0
- package/drizzle/0488_permanent_skill_removal.sql +207 -0
- package/drizzle/0489_modal_command_byte_offsets.sql +17 -0
- package/drizzle/0490_periodic_capture_attempt_cadence.sql +6 -0
- package/drizzle/0491_warm_capture_holder_reclamation.sql +57 -0
- package/drizzle/0492_codex_accepted_source_authority.sql +249 -0
- package/drizzle/0493_stopping_command_error_containment.sql +58 -0
- package/drizzle/0494_mcp_account_bindings.sql +334 -0
- package/drizzle/0495_consented_sandbox_recovery.sql +220 -0
- package/drizzle/0496_supervised_command_settlement.sql +386 -0
- package/drizzle/0497_modal_inventory_owner_read_capability.sql +112 -0
- package/drizzle/0498_enrollment_membership_fence.sql +87 -0
- package/drizzle/0499_session_attachment_access.sql +224 -0
- package/drizzle/0500_session_execution_epoch.sql +37 -0
- package/drizzle/0501_session_sharing_execution.sql +591 -0
- package/drizzle/0502_active_message_boundary_forks.sql +30 -0
- package/package.json +17 -5
- package/src/automations.ts +17 -73
- package/src/canonical-human-identities.ts +17 -5
- package/src/capability-components.ts +7 -24
- package/src/capability-integrations.ts +301 -21
- package/src/capability-reconciliation.ts +19 -0
- package/src/codex-capacity-recovery.ts +47 -0
- package/src/codex-failure-eligibility.ts +93 -0
- package/src/connect-attempts.ts +49 -18
- package/src/connection-authority.ts +12 -158
- package/src/connection-refresh-lock.ts +22 -0
- package/src/connection-token-resolver.ts +58 -530
- package/src/database-timing.ts +43 -0
- package/src/database.ts +61 -26
- package/src/editable-artifacts.ts +1 -1
- package/src/index.ts +3578 -1273
- package/src/insights-model-bundle.ts +19 -7
- package/src/insights-usage-bundle.ts +16 -19
- package/src/integration-bindings.ts +2 -7
- package/src/integration-facets.ts +73 -6
- package/src/knowledge-entries.ts +8 -1
- package/src/live-session-attempt.ts +0 -22
- package/src/mcp-account-bindings.ts +12 -0
- package/src/mcp-oauth.ts +26 -0
- package/src/organization-integration-policy.ts +235 -0
- package/src/organization-usage.ts +83 -0
- package/src/plugin-packages.ts +226 -42
- package/src/pr-review.ts +7 -69
- package/src/preference-registry-schema.ts +1 -0
- package/src/provision-roles.ts +50 -37
- package/src/retained-provider-commands.ts +286 -9
- package/src/retired-session-create-metadata.ts +16 -0
- package/src/runtime-posture.ts +217 -13
- package/src/schema.ts +104 -120
- package/src/session-admission-block.ts +29 -0
- package/src/session-attempt-writers.ts +48 -0
- package/src/session-control.ts +21 -5
- package/src/session-event-slices.ts +76 -26
- package/src/session-file-attachments.ts +66 -0
- package/src/session-goal-reports.ts +255 -0
- package/src/session-mcp-approval.ts +30 -0
- package/src/session-message-search.ts +348 -0
- package/src/session-queue-commands.ts +60 -36
- package/src/session-retry.ts +319 -0
- package/src/skill-config-migration.ts +11 -2
- package/src/skill-source-release-impact.ts +33 -0
- package/src/skill-source-release.ts +67 -26
- package/src/skills.ts +44 -6
- package/src/user-resource-authority.ts +0 -56
- package/dist/chunk-6T2GGYWE.js.map +0 -1
- package/dist/chunk-7HMK3B45.js.map +0 -1
- package/dist/chunk-DPONPYJD.js.map +0 -1
- package/dist/chunk-F73UKJY6.js.map +0 -1
- package/dist/chunk-T6YLHJLS.js.map +0 -1
- package/dist/host-mcp-binding-match.d.ts +0 -5
- package/dist/host-mcp-bindings.d.ts +0 -79
- package/dist/host-mcp-resolvers.d.ts +0 -47
- package/dist/host-mcp-task-authority.d.ts +0 -43
- package/dist/host-selection-identity.d.ts +0 -6
- package/dist/pack-components.d.ts +0 -83
- package/dist/pack-installations.d.ts +0 -86
- package/src/host-mcp-binding-match.ts +0 -34
- package/src/host-mcp-bindings.ts +0 -777
- package/src/host-mcp-resolvers.ts +0 -266
- package/src/host-mcp-task-authority.ts +0 -384
- package/src/host-selection-identity.ts +0 -29
- package/src/pack-components.ts +0 -980
- package/src/pack-installations.ts +0 -950
- /package/dist/{chunk-MWMXWHJD.js.map → chunk-7JCDSMX2.js.map} +0 -0
- /package/dist/{chunk-ERKVSPDX.js.map → chunk-LVY33EWL.js.map} +0 -0
- /package/dist/{chunk-T6BWIGWJ.js.map → chunk-RIYHP2WU.js.map} +0 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { and, asc, eq, sql, type SQL } from "drizzle-orm";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import type {
|
|
5
|
+
SessionMessageSearchRequest,
|
|
6
|
+
SessionMessageSearchMatch,
|
|
7
|
+
SessionMessageSearchResponse,
|
|
8
|
+
} from "@opengeni/contracts";
|
|
9
|
+
import type { Database } from "./database";
|
|
10
|
+
import * as schema from "./schema";
|
|
11
|
+
import { readSessionMessageSliceInScope } from "./session-event-slices";
|
|
12
|
+
import { fromPostgresLosslessJson, LOSSLESS_JSON_STRING_PREFIX } from "./lossless-json";
|
|
13
|
+
|
|
14
|
+
const Position = z
|
|
15
|
+
.object({
|
|
16
|
+
sessionId: z.string().uuid(),
|
|
17
|
+
sequence: z.number().int().min(1).max(2_147_483_647),
|
|
18
|
+
offset: z.number().int().min(0).max(2_147_483_647),
|
|
19
|
+
utf16Offset: z.number().int().min(0).max(4_294_967_294),
|
|
20
|
+
minimumMatchOffset: z.number().int().min(0).max(4_294_967_294),
|
|
21
|
+
matched: z.boolean(),
|
|
22
|
+
done: z.boolean(),
|
|
23
|
+
skipSession: z.boolean().optional(),
|
|
24
|
+
})
|
|
25
|
+
.strict();
|
|
26
|
+
const Cursor = z
|
|
27
|
+
.object({
|
|
28
|
+
version: z.literal(1),
|
|
29
|
+
binding: z.string().regex(/^[a-f0-9]{64}$/),
|
|
30
|
+
position: Position,
|
|
31
|
+
scanned: z.number().int().nonnegative().safe(),
|
|
32
|
+
matched: z.number().int().nonnegative().safe(),
|
|
33
|
+
occurrences: z.number().int().nonnegative().safe(),
|
|
34
|
+
})
|
|
35
|
+
.strict();
|
|
36
|
+
type Position = z.infer<typeof Position>;
|
|
37
|
+
|
|
38
|
+
export class SessionMessageSearchCursorError extends Error {
|
|
39
|
+
constructor() {
|
|
40
|
+
super("Invalid session message search cursor or changed search scope");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** ECMAScript Unicode simple case folding, not locale-sensitive lowercasing.
|
|
45
|
+
* Escaping every regexp metacharacter makes %, _, backslash, etc. literal too.
|
|
46
|
+
* RegExp indices refer to original UTF-16 text (no lowercased-offset drift).
|
|
47
|
+
*/
|
|
48
|
+
export function sessionMessageLiteralPattern(query: string): RegExp {
|
|
49
|
+
return new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "iu");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function sessionMessageSearchSnippet(text: string, start: number, length: number) {
|
|
53
|
+
let left = Math.max(0, start - 120);
|
|
54
|
+
let right = Math.min(text.length, start + length + 120);
|
|
55
|
+
if (left > 0 && /[\uDC00-\uDFFF]/.test(text[left]!)) left--;
|
|
56
|
+
if (right < text.length && /[\uDC00-\uDFFF]/.test(text[right]!)) right++;
|
|
57
|
+
return {
|
|
58
|
+
text: text.slice(left, right),
|
|
59
|
+
matchStart: start - left,
|
|
60
|
+
matchEnd: start + length - left,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Internal executor: caller holds subject RLS, session-tenancy and membership
|
|
65
|
+
* fences and supplies the ordinary session list filters. Never call as auth.
|
|
66
|
+
* Work/transfer is bounded by 32 scalar windows per request. No history cutoff:
|
|
67
|
+
* an unfinished scan ALWAYS returns an advancing cursor, even with zero hits.
|
|
68
|
+
*/
|
|
69
|
+
export async function scanSessionMessages(
|
|
70
|
+
db: Database,
|
|
71
|
+
workspaceId: string,
|
|
72
|
+
request: SessionMessageSearchRequest,
|
|
73
|
+
filters: SQL[],
|
|
74
|
+
authorityIdentity: unknown,
|
|
75
|
+
signal?: AbortSignal,
|
|
76
|
+
): Promise<SessionMessageSearchResponse> {
|
|
77
|
+
signal?.throwIfAborted();
|
|
78
|
+
const started = performance.now();
|
|
79
|
+
const binding = createHash("sha256")
|
|
80
|
+
.update(
|
|
81
|
+
JSON.stringify([
|
|
82
|
+
workspaceId,
|
|
83
|
+
authorityIdentity,
|
|
84
|
+
request.query,
|
|
85
|
+
request.sessionId ?? null,
|
|
86
|
+
request.archiveStatus ?? "active",
|
|
87
|
+
...(request.groupBy ? [{ groupBy: request.groupBy }] : []),
|
|
88
|
+
]),
|
|
89
|
+
)
|
|
90
|
+
.digest("hex");
|
|
91
|
+
let position: Position | null = null;
|
|
92
|
+
let scanned = 0;
|
|
93
|
+
let matched = 0;
|
|
94
|
+
let occurrences = 0;
|
|
95
|
+
if (request.cursor) {
|
|
96
|
+
try {
|
|
97
|
+
const cursor = Cursor.parse(
|
|
98
|
+
JSON.parse(Buffer.from(request.cursor, "base64url").toString("utf8")),
|
|
99
|
+
);
|
|
100
|
+
if (
|
|
101
|
+
cursor.binding !== binding ||
|
|
102
|
+
cursor.matched > cursor.scanned ||
|
|
103
|
+
cursor.matched > cursor.occurrences ||
|
|
104
|
+
(cursor.position.skipSession &&
|
|
105
|
+
(request.groupBy !== "session" || !cursor.position.done || !cursor.position.matched))
|
|
106
|
+
)
|
|
107
|
+
throw new Error();
|
|
108
|
+
position = cursor.position;
|
|
109
|
+
scanned = cursor.scanned;
|
|
110
|
+
matched = cursor.matched;
|
|
111
|
+
occurrences = cursor.occurrences;
|
|
112
|
+
} catch {
|
|
113
|
+
throw new SessionMessageSearchCursorError();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const pattern = new RegExp(sessionMessageLiteralPattern(request.query), "giu");
|
|
117
|
+
const matches: SessionMessageSearchMatch[] = [];
|
|
118
|
+
let exhausted = false;
|
|
119
|
+
const e = schema.sessionEvents;
|
|
120
|
+
// One bounded batch for ordinary complete messages. Large scalar continuations
|
|
121
|
+
// alone use the existing lossless slice reader. There is no per-message SQL
|
|
122
|
+
// round trip for the common small-message/no-hit path.
|
|
123
|
+
{
|
|
124
|
+
const boundary = position
|
|
125
|
+
? position.skipSession
|
|
126
|
+
? sql`${e.sessionId} > ${position.sessionId}::uuid`
|
|
127
|
+
: sql`(${e.sessionId} > ${position.sessionId}::uuid or (${e.sessionId} = ${position.sessionId}::uuid and ${position.done ? sql`${e.sequence} > ${position.sequence}` : sql`${e.sequence} >= ${position.sequence}`}))`
|
|
128
|
+
: sql`true`;
|
|
129
|
+
// Correlate the exact durable message identity, not turn status or latest
|
|
130
|
+
// model context. The latest full completion for a provider message wins,
|
|
131
|
+
// so an earlier shorter completion cannot hide later retained text. Same-
|
|
132
|
+
// text distinct provider messages remain distinct; the id-less final
|
|
133
|
+
// settlement copy is suppressed against its earlier complete text.
|
|
134
|
+
// Suppression requires the competing copy to retain searchable string text
|
|
135
|
+
// itself: a later text-less completion (failed/empty retry sharing the
|
|
136
|
+
// provider message id) must never hide the earlier complete text.
|
|
137
|
+
const identities = await db
|
|
138
|
+
.select({
|
|
139
|
+
sessionId: e.sessionId,
|
|
140
|
+
eventId: e.id,
|
|
141
|
+
sequence: e.sequence,
|
|
142
|
+
turnId: e.turnId,
|
|
143
|
+
type: sql<"user.message" | "agent.message.completed">`${e.type}`,
|
|
144
|
+
sessionTitle: sql<
|
|
145
|
+
string | null
|
|
146
|
+
>`case when octet_length(${schema.sessions.title}) <= 2048 then ${schema.sessions.title} else null end`,
|
|
147
|
+
messageId: sql<unknown>`case when octet_length((${e.payload}->'messageId')::text) <= 2048 then ${e.payload}->'messageId' else null end`,
|
|
148
|
+
codec: e.payloadCodecVersion,
|
|
149
|
+
smallText: sql<unknown>`case when octet_length(${e.payload}->>'text') <= 8192 then ${e.payload}->'text' else null end`,
|
|
150
|
+
})
|
|
151
|
+
.from(e)
|
|
152
|
+
.innerJoin(
|
|
153
|
+
schema.sessions,
|
|
154
|
+
and(eq(schema.sessions.workspaceId, e.workspaceId), eq(schema.sessions.id, e.sessionId)),
|
|
155
|
+
)
|
|
156
|
+
.where(
|
|
157
|
+
and(
|
|
158
|
+
eq(e.workspaceId, workspaceId),
|
|
159
|
+
...filters,
|
|
160
|
+
boundary,
|
|
161
|
+
request.sessionId ? eq(e.sessionId, request.sessionId) : sql`true`,
|
|
162
|
+
sql`${e.type} in ('user.message', 'agent.message.completed')`,
|
|
163
|
+
sql`(${e.turnAssociation} is null or ${e.turnAssociation} = 'current')`,
|
|
164
|
+
sql`${e.duplicateOfEventId} is null`,
|
|
165
|
+
sql`jsonb_typeof(${e.payload}->'text') = 'string'`,
|
|
166
|
+
sql`(${e.type} <> 'user.message' or not exists (
|
|
167
|
+
select 1 from ${schema.sessionTurns} unclaimed
|
|
168
|
+
where unclaimed.workspace_id = ${workspaceId} and unclaimed.session_id = ${e.sessionId}
|
|
169
|
+
and unclaimed.trigger_event_id = ${e.id} and unclaimed.source in ('user', 'api')
|
|
170
|
+
and unclaimed.started_at is null))`,
|
|
171
|
+
sql`(${e.type} <> 'agent.message.completed' or not exists (
|
|
172
|
+
select 1 from ${schema.sessionEvents} other_message
|
|
173
|
+
where other_message.workspace_id = ${workspaceId} and other_message.session_id = ${e.sessionId}
|
|
174
|
+
and other_message.turn_id = ${e.turnId}
|
|
175
|
+
and other_message.type = 'agent.message.completed' and other_message.duplicate_of_event_id is null
|
|
176
|
+
and (other_message.turn_association is null or other_message.turn_association = 'current')
|
|
177
|
+
and jsonb_typeof(other_message.payload->'text') = 'string'
|
|
178
|
+
and ((jsonb_typeof(${e.payload}->'messageId') = 'string'
|
|
179
|
+
and other_message.sequence > ${e.sequence}
|
|
180
|
+
and other_message.payload->'messageId' = ${e.payload}->'messageId'
|
|
181
|
+
and (other_message.payload_codec_version is not distinct from ${e.payloadCodecVersion}
|
|
182
|
+
or left(${e.payload}->>'messageId', ${LOSSLESS_JSON_STRING_PREFIX.length}) <> ${LOSSLESS_JSON_STRING_PREFIX}))
|
|
183
|
+
or (coalesce(${e.payload}->>'messageId', '') = ''
|
|
184
|
+
and other_message.sequence < ${e.sequence}
|
|
185
|
+
and other_message.payload->'text' = ${e.payload}->'text'
|
|
186
|
+
and (other_message.payload_codec_version is not distinct from ${e.payloadCodecVersion}
|
|
187
|
+
or left(${e.payload}->>'text', ${LOSSLESS_JSON_STRING_PREFIX.length}) <> ${LOSSLESS_JSON_STRING_PREFIX})))))`,
|
|
188
|
+
),
|
|
189
|
+
)
|
|
190
|
+
.orderBy(asc(e.sessionId), asc(e.sequence))
|
|
191
|
+
.limit(33);
|
|
192
|
+
let identityIndex = 0;
|
|
193
|
+
for (let window = 0; window < 32 && matches.length < (request.limit ?? 20); window++) {
|
|
194
|
+
signal?.throwIfAborted();
|
|
195
|
+
if (window > 0 && performance.now() - started >= 1_500) break;
|
|
196
|
+
const identity = identities[identityIndex];
|
|
197
|
+
if (!identity) {
|
|
198
|
+
// Grouping can drain a full candidate batch in fewer than 32 windows.
|
|
199
|
+
// A full batch is not proof that later sessions do not exist.
|
|
200
|
+
exhausted = identities.length < 33;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
const continuing =
|
|
204
|
+
position &&
|
|
205
|
+
!position.done &&
|
|
206
|
+
position.sessionId === identity.sessionId &&
|
|
207
|
+
position.sequence === identity.sequence;
|
|
208
|
+
if (!continuing) {
|
|
209
|
+
scanned++;
|
|
210
|
+
position = {
|
|
211
|
+
sessionId: identity.sessionId,
|
|
212
|
+
sequence: identity.sequence,
|
|
213
|
+
offset: 0,
|
|
214
|
+
utf16Offset: 0,
|
|
215
|
+
minimumMatchOffset: 0,
|
|
216
|
+
matched: false,
|
|
217
|
+
done: false,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const offset = position!.offset;
|
|
221
|
+
const utf16Offset = position!.utf16Offset;
|
|
222
|
+
const smallText = fromPostgresLosslessJson(identity.smallText, identity.codec);
|
|
223
|
+
// Amortize full-source detoasting/codec validation over adjacent windows,
|
|
224
|
+
// not a larger request budget. A four-window read consumes four of the
|
|
225
|
+
// original 32 slots, even if a match/short source ends it early.
|
|
226
|
+
const scalarWindows = typeof smallText === "string" ? 1 : Math.min(4, 32 - window);
|
|
227
|
+
const slice =
|
|
228
|
+
typeof smallText === "string"
|
|
229
|
+
? {
|
|
230
|
+
offset: 0,
|
|
231
|
+
total: smallText.length,
|
|
232
|
+
unit: "utf16" as const,
|
|
233
|
+
text: smallText,
|
|
234
|
+
omitted: false,
|
|
235
|
+
}
|
|
236
|
+
: await readSessionMessageSliceInScope(
|
|
237
|
+
db,
|
|
238
|
+
workspaceId,
|
|
239
|
+
identity.sessionId,
|
|
240
|
+
{
|
|
241
|
+
id: identity.eventId,
|
|
242
|
+
sequence: identity.sequence,
|
|
243
|
+
type: identity.type,
|
|
244
|
+
turnId: identity.turnId,
|
|
245
|
+
turnAssociation: null,
|
|
246
|
+
duplicateOfEventId: null,
|
|
247
|
+
},
|
|
248
|
+
offset,
|
|
249
|
+
scalarWindows,
|
|
250
|
+
);
|
|
251
|
+
window += scalarWindows - 1;
|
|
252
|
+
if (!slice || slice.omitted) {
|
|
253
|
+
// Deletion/visibility changes never turn into a fabricated message.
|
|
254
|
+
position = { ...position!, done: true };
|
|
255
|
+
identityIndex++;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
pattern.lastIndex = Math.max(0, position!.minimumMatchOffset - utf16Offset);
|
|
259
|
+
let found: RegExpExecArray | null;
|
|
260
|
+
const messageId = fromPostgresLosslessJson(identity.messageId, identity.codec);
|
|
261
|
+
while (matches.length < (request.limit ?? 20) && (found = pattern.exec(slice.text))) {
|
|
262
|
+
matches.push({
|
|
263
|
+
sessionId: identity.sessionId,
|
|
264
|
+
sessionTitle: identity.sessionTitle,
|
|
265
|
+
eventId: identity.eventId,
|
|
266
|
+
sequence: identity.sequence,
|
|
267
|
+
turnId: identity.turnId,
|
|
268
|
+
role: identity.type === "user.message" ? "user" : "assistant",
|
|
269
|
+
messageId: typeof messageId === "string" ? messageId : null,
|
|
270
|
+
messageMatchOffset: utf16Offset + found.index,
|
|
271
|
+
snippet: sessionMessageSearchSnippet(slice.text, found.index, found[0].length),
|
|
272
|
+
});
|
|
273
|
+
if (!position!.matched) matched++;
|
|
274
|
+
occurrences++;
|
|
275
|
+
position = {
|
|
276
|
+
...position!,
|
|
277
|
+
matched: true,
|
|
278
|
+
minimumMatchOffset: utf16Offset + found.index + found[0].length,
|
|
279
|
+
};
|
|
280
|
+
if (request.groupBy === "session") {
|
|
281
|
+
position = { ...position, done: true, skipSession: true };
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (position!.skipSession) {
|
|
286
|
+
// Skip both buffered messages and all unbuffered history of this
|
|
287
|
+
// matching session. The next cursor carries a strict session boundary,
|
|
288
|
+
// so a prolific message cannot flood the workspace picker with pages.
|
|
289
|
+
do {
|
|
290
|
+
identityIndex++;
|
|
291
|
+
} while (identities[identityIndex]?.sessionId === identity.sessionId);
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const units = slice.unit === "utf16" ? slice.text.length : Array.from(slice.text).length;
|
|
295
|
+
if (matches.length >= (request.limit ?? 20)) {
|
|
296
|
+
if (
|
|
297
|
+
offset + units >= slice.total &&
|
|
298
|
+
position!.minimumMatchOffset >= utf16Offset + slice.text.length
|
|
299
|
+
) {
|
|
300
|
+
position = { ...position!, done: true };
|
|
301
|
+
identityIndex++;
|
|
302
|
+
}
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
if (offset + units >= slice.total) {
|
|
306
|
+
position = { ...position!, done: true };
|
|
307
|
+
identityIndex++;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
// Overlap enough complete scalars for every literal crossing a window.
|
|
311
|
+
// Retain additional preceding snippet context; resume offset is absolute
|
|
312
|
+
// UTF-16 so supplementary characters and lossless code units cannot drift.
|
|
313
|
+
const overlap = request.query.length * 2 + 122;
|
|
314
|
+
let advance = Math.max(1, units - overlap);
|
|
315
|
+
let prefix =
|
|
316
|
+
slice.unit === "utf16"
|
|
317
|
+
? slice.text.slice(0, advance)
|
|
318
|
+
: Array.from(slice.text).slice(0, advance).join("");
|
|
319
|
+
if (slice.unit === "utf16" && /[\uD800-\uDBFF]/.test(prefix.at(-1)!)) {
|
|
320
|
+
advance--;
|
|
321
|
+
prefix = prefix.slice(0, -1);
|
|
322
|
+
}
|
|
323
|
+
position = {
|
|
324
|
+
...position!,
|
|
325
|
+
offset: offset + advance,
|
|
326
|
+
utf16Offset: utf16Offset + prefix.length,
|
|
327
|
+
minimumMatchOffset: Math.max(position!.minimumMatchOffset, utf16Offset + prefix.length),
|
|
328
|
+
done: false,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
if (identityIndex >= identities.length && identities.length < 33) exhausted = true;
|
|
332
|
+
}
|
|
333
|
+
signal?.throwIfAborted();
|
|
334
|
+
return {
|
|
335
|
+
matches,
|
|
336
|
+
hasMore: !exhausted,
|
|
337
|
+
countIsExact: exhausted,
|
|
338
|
+
scannedMessages: scanned,
|
|
339
|
+
matchedMessageCount: matched,
|
|
340
|
+
matchedOccurrenceCount: occurrences,
|
|
341
|
+
nextCursor:
|
|
342
|
+
exhausted || !position
|
|
343
|
+
? null
|
|
344
|
+
: Buffer.from(
|
|
345
|
+
JSON.stringify({ version: 1, binding, position, scanned, matched, occurrences }),
|
|
346
|
+
).toString("base64url"),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { acceptSessionFileAttachments } from "./session-file-attachments";
|
|
1
2
|
import { withLatestStartedSessionPolicy } from "./session-execution-policy";
|
|
3
|
+
import { parseAcceptedMcpAccountBindings } from "./mcp-account-bindings";
|
|
2
4
|
import {
|
|
3
5
|
WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1,
|
|
4
6
|
XaiProviderAccountAuthoritySnapshotV1,
|
|
@@ -14,6 +16,7 @@ import {
|
|
|
14
16
|
stableJson,
|
|
15
17
|
turnExecutionPolicyAuditMetadata,
|
|
16
18
|
type McpPersonalConnectionDelegation,
|
|
19
|
+
type McpConnectionAccountBinding,
|
|
17
20
|
type DraftTimelineAnnotation,
|
|
18
21
|
type LatencyMode,
|
|
19
22
|
type ReasoningEffort,
|
|
@@ -31,7 +34,12 @@ import {
|
|
|
31
34
|
type PersonalResourceAttachmentIntent,
|
|
32
35
|
} from "@opengeni/contracts";
|
|
33
36
|
import { and, asc, desc, eq, inArray, sql } from "drizzle-orm";
|
|
34
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
withSessionRlsActorContext,
|
|
39
|
+
setSubjectRlsContext,
|
|
40
|
+
type Database,
|
|
41
|
+
type SessionActivityDatabase,
|
|
42
|
+
} from "./database";
|
|
35
43
|
import {
|
|
36
44
|
fromPostgresLosslessJson,
|
|
37
45
|
fromPostgresLosslessText,
|
|
@@ -347,14 +355,15 @@ async function personalConnectionDelegationsForAgentActor(
|
|
|
347
355
|
db: Database,
|
|
348
356
|
workspaceId: string,
|
|
349
357
|
actor: Extract<SessionCommandActor, { type: "agent_attempt" }>,
|
|
350
|
-
targetSessionId: string,
|
|
351
358
|
): Promise<{
|
|
352
359
|
delegations: McpPersonalConnectionDelegation[];
|
|
360
|
+
mcpAccountBindings: McpConnectionAccountBinding[] | null;
|
|
353
361
|
connectionAuthoritySubjectId: string | null;
|
|
354
362
|
}> {
|
|
355
363
|
const [row] = await db
|
|
356
364
|
.select({
|
|
357
365
|
delegations: schema.sessionTurns.personalConnectionDelegations,
|
|
366
|
+
mcpAccountBindings: schema.sessionTurns.mcpAccountBindings,
|
|
358
367
|
initiatingHumanSubjectId: schema.sessionTurns.initiatingHumanSubjectId,
|
|
359
368
|
})
|
|
360
369
|
.from(schema.sessionTurns)
|
|
@@ -377,22 +386,11 @@ async function personalConnectionDelegationsForAgentActor(
|
|
|
377
386
|
`Agent authority turn has malformed personal MCP delegation state: ${actor.sessionId}/${actor.turnId}`,
|
|
378
387
|
);
|
|
379
388
|
}
|
|
380
|
-
//
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
.filter((delegation) => {
|
|
386
|
-
const authority = delegation.userDelegation;
|
|
387
|
-
if (!authority) return true;
|
|
388
|
-
if (authority.mode === "once") return false;
|
|
389
|
-
if (authority.mode === "session") return authority.sessionId === targetSessionId;
|
|
390
|
-
return true;
|
|
391
|
-
})
|
|
392
|
-
.map((delegation) => ({ ...delegation }));
|
|
393
|
-
const activated = delegations.filter((delegation) => delegation.userDelegation);
|
|
394
|
-
if (activated.length === 0) {
|
|
395
|
-
return { delegations, connectionAuthoritySubjectId: null };
|
|
389
|
+
// New agent work inherits the exact originating turn's sender and accounts.
|
|
390
|
+
const delegations = parsed.data.map((delegation) => ({ ...delegation }));
|
|
391
|
+
const mcpAccountBindings = parseAcceptedMcpAccountBindings(row.mcpAccountBindings);
|
|
392
|
+
if (delegations.length === 0) {
|
|
393
|
+
return { delegations, mcpAccountBindings, connectionAuthoritySubjectId: null };
|
|
396
394
|
}
|
|
397
395
|
const connectionAuthoritySubjectId = row.initiatingHumanSubjectId;
|
|
398
396
|
if (!connectionAuthoritySubjectId) {
|
|
@@ -400,14 +398,14 @@ async function personalConnectionDelegationsForAgentActor(
|
|
|
400
398
|
`Agent authority turn lost its causal human: ${actor.sessionId}/${actor.turnId}`,
|
|
401
399
|
);
|
|
402
400
|
}
|
|
403
|
-
for (const delegation of
|
|
401
|
+
for (const delegation of delegations) {
|
|
404
402
|
if (delegation.ownerSubjectId !== connectionAuthoritySubjectId) {
|
|
405
403
|
throw new SessionControlInvariantError(
|
|
406
404
|
`Agent authority turn causal human does not own retained connection authority: ${actor.sessionId}/${actor.turnId}`,
|
|
407
405
|
);
|
|
408
406
|
}
|
|
409
407
|
}
|
|
410
|
-
return { delegations, connectionAuthoritySubjectId };
|
|
408
|
+
return { delegations, mcpAccountBindings, connectionAuthoritySubjectId };
|
|
411
409
|
}
|
|
412
410
|
|
|
413
411
|
async function xaiAuthorityForAgentActor(
|
|
@@ -1759,6 +1757,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
1759
1757
|
/** Record the admitted run's durable usage fact in this transaction. */
|
|
1760
1758
|
recordAgentRunUsage?: boolean;
|
|
1761
1759
|
personalConnectionDelegations?: McpPersonalConnectionDelegation[];
|
|
1760
|
+
mcpAccountBindings?: McpConnectionAccountBinding[] | null;
|
|
1762
1761
|
personalResourceAttachment?: PersonalResourceAttachmentIntent;
|
|
1763
1762
|
mcpCredentialUpdates?: Array<{
|
|
1764
1763
|
id: string;
|
|
@@ -1769,11 +1768,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
1769
1768
|
beforeFreshPromptCommit?: (tx: Database) => Promise<void>;
|
|
1770
1769
|
/** Backend-only authority capture, atomic with the newly accepted turn. */
|
|
1771
1770
|
captureTurnAuthority?: (tx: Database, turnId: string) => Promise<void>;
|
|
1772
|
-
|
|
1773
|
-
serverId: string;
|
|
1774
|
-
delegationId: string;
|
|
1775
|
-
generation: number;
|
|
1776
|
-
}>;
|
|
1771
|
+
|
|
1777
1772
|
/** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
|
|
1778
1773
|
controlLockTimeoutMs?: number;
|
|
1779
1774
|
},
|
|
@@ -1829,10 +1824,9 @@ export async function submitHumanPromptInTransaction(
|
|
|
1829
1824
|
mirrorToRealtime: input.mirrorToRealtime ?? true,
|
|
1830
1825
|
mcpCredentialUpdates: input.mcpCredentialUpdates ?? [],
|
|
1831
1826
|
personalConnectionDelegations: input.personalConnectionDelegations ?? [],
|
|
1827
|
+
mcpAccountBindings: input.mcpAccountBindings ?? null,
|
|
1832
1828
|
personalResourceAttachment: input.personalResourceAttachment ?? null,
|
|
1833
|
-
|
|
1834
|
-
? { selectedHostMcpDelegations: input.selectedHostMcpDelegations }
|
|
1835
|
-
: {}),
|
|
1829
|
+
|
|
1836
1830
|
...(input.actor.type === "service"
|
|
1837
1831
|
? {
|
|
1838
1832
|
serviceInitiator: {
|
|
@@ -1923,6 +1917,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
1923
1917
|
!isQueueEditSubmission &&
|
|
1924
1918
|
before.state === "active" &&
|
|
1925
1919
|
session.status === "requires_action" &&
|
|
1920
|
+
!session.admissionBlock &&
|
|
1926
1921
|
session.activeTurnId !== null
|
|
1927
1922
|
? "steer"
|
|
1928
1923
|
: input.delivery;
|
|
@@ -2082,9 +2077,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2082
2077
|
: (frozenInitiator.initiatingHumanSubjectId ??
|
|
2083
2078
|
(frozenInitiator.initiator.kind === "subject" ? frozenInitiator.initiator.subjectId : null));
|
|
2084
2079
|
if (
|
|
2085
|
-
(input.personalConnectionDelegations ?? []).
|
|
2086
|
-
(delegation) => delegation.userDelegation !== undefined,
|
|
2087
|
-
) ||
|
|
2080
|
+
(input.personalConnectionDelegations ?? []).length > 0 ||
|
|
2088
2081
|
input.personalResourceAttachment !== undefined
|
|
2089
2082
|
) {
|
|
2090
2083
|
if (!acceptedInitiatingHumanSubjectId) {
|
|
@@ -2194,6 +2187,9 @@ export async function submitHumanPromptInTransaction(
|
|
|
2194
2187
|
personalConnectionDelegations: editedSourceTurn
|
|
2195
2188
|
? editedSourceTurn.personalConnectionDelegations
|
|
2196
2189
|
: (input.personalConnectionDelegations ?? []),
|
|
2190
|
+
mcpAccountBindings: editedSourceTurn
|
|
2191
|
+
? editedSourceTurn.mcpAccountBindings
|
|
2192
|
+
: parseAcceptedMcpAccountBindings(input.mcpAccountBindings),
|
|
2197
2193
|
xaiProviderAccountAuthoritySnapshot,
|
|
2198
2194
|
createdAt: now,
|
|
2199
2195
|
updatedAt: now,
|
|
@@ -2398,7 +2394,9 @@ export async function submitHumanPromptInTransaction(
|
|
|
2398
2394
|
);
|
|
2399
2395
|
const noCurrentAfter =
|
|
2400
2396
|
effectiveDelivery === "steer" ? liveCurrentTurnId === null : !session.activeTurnId;
|
|
2401
|
-
const nextStatus = noCurrentAfter
|
|
2397
|
+
const nextStatus = noCurrentAfter
|
|
2398
|
+
? "queued"
|
|
2399
|
+
: (session.admissionBlock?.previousStatus ?? session.status);
|
|
2402
2400
|
if (nextStatus !== session.status) {
|
|
2403
2401
|
eventValues.push({
|
|
2404
2402
|
accountId: input.accountId,
|
|
@@ -2414,6 +2412,24 @@ export async function submitHumanPromptInTransaction(
|
|
|
2414
2412
|
.insert(schema.sessionEvents)
|
|
2415
2413
|
.values(withLosslessContentWriteVersion(eventValues, "payload", "payloadCodecVersion"))
|
|
2416
2414
|
.returning();
|
|
2415
|
+
// Shared acceptance boundary covers ordinary Send/Steer and realtime. Only the
|
|
2416
|
+
// verified human command can share original uploads; inherited agent identity
|
|
2417
|
+
// is deliberately insufficient. Events must exist before grant provenance is checked.
|
|
2418
|
+
if (input.actor.type === "human" && input.actor.subjectId === input.subjectId) {
|
|
2419
|
+
await withSessionRlsActorContext(
|
|
2420
|
+
{ subjectId: input.subjectId, privateFileOwnerSubjectId: input.subjectId },
|
|
2421
|
+
() =>
|
|
2422
|
+
acceptSessionFileAttachments(db, {
|
|
2423
|
+
accountId: input.accountId,
|
|
2424
|
+
workspaceId: input.workspaceId,
|
|
2425
|
+
sessionId: input.sessionId,
|
|
2426
|
+
turnId: turn.id,
|
|
2427
|
+
subjectId: input.subjectId,
|
|
2428
|
+
resources: [...ResourceRef.array().parse(session.resources), ...input.resources],
|
|
2429
|
+
}),
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2417
2433
|
if (input.actor.type === "human" && input.mirrorToRealtime !== false) {
|
|
2418
2434
|
await mirrorSessionRealtimeContextInTransaction(db, {
|
|
2419
2435
|
accountId: input.accountId,
|
|
@@ -2445,6 +2461,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2445
2461
|
tools: session.tools,
|
|
2446
2462
|
activeTurnId: effectiveDelivery === "steer" ? liveCurrentTurnId : session.activeTurnId,
|
|
2447
2463
|
status: nextStatus,
|
|
2464
|
+
admissionBlock: null,
|
|
2448
2465
|
queueVersion,
|
|
2449
2466
|
queueHeadPosition: 0,
|
|
2450
2467
|
queueTailPosition: ordered.length,
|
|
@@ -2647,7 +2664,6 @@ export async function sendAgentMessageInTransaction(
|
|
|
2647
2664
|
db,
|
|
2648
2665
|
input.workspaceId,
|
|
2649
2666
|
input.actor,
|
|
2650
|
-
input.targetSessionId,
|
|
2651
2667
|
);
|
|
2652
2668
|
const personalConnectionDelegations = inheritedConnectionAuthority.delegations;
|
|
2653
2669
|
const xaiAuthority = await xaiAuthorityForAgentActor(db, input.workspaceId, input.actor);
|
|
@@ -2701,6 +2717,7 @@ export async function sendAgentMessageInTransaction(
|
|
|
2701
2717
|
...(xaiAuthority.subjectId ? { xaiAuthoritySubjectId: xaiAuthority.subjectId } : {}),
|
|
2702
2718
|
},
|
|
2703
2719
|
personalConnectionDelegations,
|
|
2720
|
+
mcpAccountBindings: inheritedConnectionAuthority.mcpAccountBindings,
|
|
2704
2721
|
xaiProviderAccountAuthoritySnapshot: xaiAuthority.snapshot,
|
|
2705
2722
|
state: "pending",
|
|
2706
2723
|
},
|
|
@@ -2760,7 +2777,11 @@ export async function sendAgentMessageInTransaction(
|
|
|
2760
2777
|
}
|
|
2761
2778
|
const eventIds = insertedEvents.map((event) => event.id);
|
|
2762
2779
|
const workflowId = session.temporalWorkflowId ?? `session-${session.id}`;
|
|
2763
|
-
const runnable =
|
|
2780
|
+
const runnable =
|
|
2781
|
+
!session.admissionBlock &&
|
|
2782
|
+
!realtimeActive &&
|
|
2783
|
+
session.activeTurnId === null &&
|
|
2784
|
+
effective.state === "active";
|
|
2764
2785
|
const wake = runnable
|
|
2765
2786
|
? await registerInternalUpdateWakeInTransaction(db, {
|
|
2766
2787
|
accountId: input.accountId,
|
|
@@ -2897,7 +2918,6 @@ export async function steerAgentSessionInTransaction(
|
|
|
2897
2918
|
db,
|
|
2898
2919
|
input.workspaceId,
|
|
2899
2920
|
input.actor,
|
|
2900
|
-
input.targetSessionId,
|
|
2901
2921
|
);
|
|
2902
2922
|
const personalConnectionDelegations = inheritedConnectionAuthority.delegations;
|
|
2903
2923
|
const xaiAuthority = await xaiAuthorityForAgentActor(db, input.workspaceId, input.actor);
|
|
@@ -2986,6 +3006,7 @@ export async function steerAgentSessionInTransaction(
|
|
|
2986
3006
|
...(xaiAuthority.subjectId ? { xaiAuthoritySubjectId: xaiAuthority.subjectId } : {}),
|
|
2987
3007
|
},
|
|
2988
3008
|
personalConnectionDelegations,
|
|
3009
|
+
mcpAccountBindings: inheritedConnectionAuthority.mcpAccountBindings,
|
|
2989
3010
|
xaiProviderAccountAuthoritySnapshot: xaiAuthority.snapshot,
|
|
2990
3011
|
state: "pending",
|
|
2991
3012
|
},
|
|
@@ -3095,7 +3116,10 @@ export async function steerAgentSessionInTransaction(
|
|
|
3095
3116
|
.update(schema.sessions)
|
|
3096
3117
|
.set({
|
|
3097
3118
|
activeTurnId: supersession.liveCurrentTurnId,
|
|
3098
|
-
status: supersession.liveCurrentTurnId
|
|
3119
|
+
status: supersession.liveCurrentTurnId
|
|
3120
|
+
? (session.admissionBlock?.previousStatus ?? session.status)
|
|
3121
|
+
: "queued",
|
|
3122
|
+
admissionBlock: null,
|
|
3099
3123
|
lastSequence: sequence,
|
|
3100
3124
|
updatedAt: now,
|
|
3101
3125
|
})
|