@opengeni/api-router 0.26.1 → 0.30.1
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/app.d.ts +1 -0
- package/dist/app.js +5 -3
- package/dist/auth/canonical-human-session-admission.d.ts +27 -0
- package/dist/browser-auth-broker.d.ts +20 -0
- package/dist/browser-controller-authority.d.ts +19 -1
- package/dist/browser-network-route.d.ts +8 -0
- package/dist/{chunk-JIKNR5YL.js → chunk-2PQMSRCB.js} +15518 -6863
- package/dist/chunk-2PQMSRCB.js.map +1 -0
- package/dist/controller-data-plane.d.ts +12 -0
- package/dist/http/auth.d.ts +1 -1
- package/dist/http/sse.d.ts +18 -1
- package/dist/index.js +1 -1
- package/dist/integrations/api-integrations.d.ts +2 -2
- package/dist/integrations/fiken.d.ts +233 -0
- package/dist/integrations/google-drive.d.ts +6 -6
- package/dist/integrations/provider-oauth.d.ts +0 -2
- package/dist/integrations/slack-bot.d.ts +171 -1
- package/dist/integrations/slack-interactions.d.ts +17 -5
- package/dist/interaction-holder-heartbeat.d.ts +17 -0
- package/dist/interaction-metrics.d.ts +11 -0
- package/dist/mcp/server.d.ts +3 -2
- package/dist/model-catalog.d.ts +1 -0
- package/dist/routes/canonical-human-identities.d.ts +3 -0
- package/dist/routes/channels.d.ts +3 -0
- package/dist/routes/integration-facets.d.ts +3 -0
- package/dist/routes/interaction-resources.d.ts +5 -0
- package/dist/routes/organization-memberships.d.ts +3 -0
- package/dist/routes/sessions.d.ts +2 -1
- package/dist/routes/slack-task-policy.d.ts +3 -0
- package/dist/routes/supergrok.d.ts +3 -0
- package/dist/sandbox/channel-a.d.ts +8 -1
- package/dist/sandbox/machines.d.ts +2 -2
- package/dist/sandbox/viewer.d.ts +3 -1
- package/dist/slack-reaction-files.d.ts +27 -0
- package/dist/transcription/providers/xai-subscription.d.ts +8 -0
- package/dist/xai-realtime.d.ts +26 -0
- package/dist/xai-subscription-auth.d.ts +23 -0
- package/package.json +17 -16
- package/src/app.ts +352 -49
- package/src/auth/canonical-human-session-admission.ts +116 -0
- package/src/auth/managed-auth.ts +101 -0
- package/src/browser-auth-broker.ts +155 -0
- package/src/browser-controller-authority.ts +50 -1
- package/src/browser-network-route.ts +34 -0
- package/src/controller-data-plane.ts +35 -0
- package/src/http/auth.ts +27 -9
- package/src/http/sse.ts +229 -5
- package/src/integrations/api-integrations.ts +57 -42
- package/src/integrations/fiken.ts +1230 -0
- package/src/integrations/google-drive.ts +31 -26
- package/src/integrations/provider-oauth.ts +70 -91
- package/src/integrations/slack-bot.ts +638 -9
- package/src/integrations/slack-interactions.ts +1583 -73
- package/src/interaction-holder-heartbeat.ts +95 -0
- package/src/interaction-metrics.ts +159 -0
- package/src/mcp/documents.ts +115 -6
- package/src/mcp/server.ts +865 -242
- package/src/model-catalog.ts +19 -6
- package/src/routes/api-integrations.ts +32 -29
- package/src/routes/browser-identities.ts +24 -0
- package/src/routes/browser-sessions.ts +2122 -183
- package/src/routes/canonical-human-identities.ts +156 -0
- package/src/routes/channels.ts +90 -0
- package/src/routes/computer-sessions.ts +441 -86
- package/src/routes/connections.ts +141 -4
- package/src/routes/{integration-features.ts → integration-facets.ts} +63 -63
- package/src/routes/interaction-resources.ts +595 -0
- package/src/routes/organization-memberships.ts +53 -0
- package/src/routes/plugins.ts +2 -1
- package/src/routes/sessions.ts +419 -43
- package/src/routes/skills.ts +92 -10
- package/src/routes/slack-task-policy.ts +115 -0
- package/src/routes/supergrok.ts +717 -0
- package/src/routes/transcription-recordings.ts +9 -2
- package/src/routes/transcriptions.ts +2 -1
- package/src/routes/video-generation.ts +34 -4
- package/src/routes/workspaces.ts +22 -4
- package/src/sandbox/channel-a.ts +29 -2
- package/src/sandbox/machines.ts +5 -5
- package/src/sandbox/viewer.ts +10 -3
- package/src/slack-reaction-files.ts +181 -0
- package/src/transcription/providers/xai-subscription.ts +110 -0
- package/src/transcription/service.ts +17 -2
- package/src/xai-realtime.ts +216 -0
- package/src/xai-subscription-auth.ts +132 -0
- package/dist/chunk-JIKNR5YL.js.map +0 -1
- package/dist/routes/integration-features.d.ts +0 -3
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { AccessGrant } from "@opengeni/contracts";
|
|
2
|
+
import { touchInteractionOperation, touchLeaseHolder } from "@opengeni/db";
|
|
3
|
+
import type { ApiRouteDeps } from "@opengeni/core";
|
|
4
|
+
|
|
5
|
+
const MAX_HEARTBEAT_INTERVAL_MS = 10_000;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Keep one durable interaction operation—and its sandbox holder when present—
|
|
9
|
+
* live while a bounded controller mutation is in flight. Browser profile
|
|
10
|
+
* capture/restore can legitimately take minutes; without this pulse a lifecycle
|
|
11
|
+
* reaper cannot distinguish that request from a caller that disappeared.
|
|
12
|
+
*/
|
|
13
|
+
export async function withInteractionHolderHeartbeat<T>(
|
|
14
|
+
deps: ApiRouteDeps,
|
|
15
|
+
input: {
|
|
16
|
+
grant: AccessGrant;
|
|
17
|
+
workspaceId: string;
|
|
18
|
+
sandboxGroupId: string | null;
|
|
19
|
+
holderId: string;
|
|
20
|
+
operationId: string;
|
|
21
|
+
resourceId: string;
|
|
22
|
+
controllerGeneration: string;
|
|
23
|
+
},
|
|
24
|
+
run: () => Promise<T>,
|
|
25
|
+
): Promise<T> {
|
|
26
|
+
const intervalMs = Math.max(
|
|
27
|
+
1_000,
|
|
28
|
+
Math.min(
|
|
29
|
+
MAX_HEARTBEAT_INTERVAL_MS,
|
|
30
|
+
Math.floor(deps.settings.sandboxInteractionHolderTtlMs / 3),
|
|
31
|
+
),
|
|
32
|
+
);
|
|
33
|
+
let stopped = false;
|
|
34
|
+
let authorityLost = false;
|
|
35
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
36
|
+
let pending: Promise<void> = Promise.resolve();
|
|
37
|
+
|
|
38
|
+
const pulse = async (): Promise<void> => {
|
|
39
|
+
try {
|
|
40
|
+
const [operationAlive, holderAlive] = await Promise.all([
|
|
41
|
+
touchInteractionOperation(deps.db, {
|
|
42
|
+
accountId: input.grant.accountId,
|
|
43
|
+
workspaceId: input.workspaceId,
|
|
44
|
+
operationId: input.operationId,
|
|
45
|
+
resourceId: input.resourceId,
|
|
46
|
+
controllerGeneration: input.controllerGeneration,
|
|
47
|
+
}),
|
|
48
|
+
input.sandboxGroupId
|
|
49
|
+
? touchLeaseHolder(deps.db, {
|
|
50
|
+
accountId: input.grant.accountId,
|
|
51
|
+
workspaceId: input.workspaceId,
|
|
52
|
+
sandboxGroupId: input.sandboxGroupId,
|
|
53
|
+
kind: "interaction",
|
|
54
|
+
holderId: input.holderId,
|
|
55
|
+
})
|
|
56
|
+
: Promise.resolve(true),
|
|
57
|
+
]);
|
|
58
|
+
if (!operationAlive || !holderAlive) authorityLost = true;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
// A transient database error does not surrender controller authority. The
|
|
61
|
+
// next pulse can recover, and the operation's authoritative settlement
|
|
62
|
+
// still goes through the database before it is exposed as complete.
|
|
63
|
+
deps.observability?.warn("interaction holder heartbeat failed", {
|
|
64
|
+
workspaceId: input.workspaceId,
|
|
65
|
+
sandboxGroupId: input.sandboxGroupId,
|
|
66
|
+
holderId: input.holderId,
|
|
67
|
+
error: error instanceof Error ? error.message : String(error),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const schedule = (): void => {
|
|
72
|
+
if (stopped) return;
|
|
73
|
+
timer = setTimeout(() => {
|
|
74
|
+
pending = pulse().finally(schedule);
|
|
75
|
+
}, intervalMs);
|
|
76
|
+
timer.unref?.();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
await pulse();
|
|
80
|
+
if (authorityLost) {
|
|
81
|
+
throw new Error("Interaction controller placement authority was lost");
|
|
82
|
+
}
|
|
83
|
+
schedule();
|
|
84
|
+
try {
|
|
85
|
+
const result = await run();
|
|
86
|
+
if (authorityLost) {
|
|
87
|
+
throw new Error("Interaction controller placement authority was lost");
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
} finally {
|
|
91
|
+
stopped = true;
|
|
92
|
+
if (timer) clearTimeout(timer);
|
|
93
|
+
await pending;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthRunMutationResponse,
|
|
3
|
+
BrowserActionReceipt,
|
|
4
|
+
BrowserActionRequest,
|
|
5
|
+
PublishBrowserRevisionResponse,
|
|
6
|
+
BrowserSessionMutationResponse,
|
|
7
|
+
ComputerActionReceipt,
|
|
8
|
+
ComputerActionRequest,
|
|
9
|
+
ComputerSessionMutationResponse,
|
|
10
|
+
InteractionInterventionMutationResponse,
|
|
11
|
+
ProtectedAuthFillResponse,
|
|
12
|
+
} from "@opengeni/contracts";
|
|
13
|
+
import {
|
|
14
|
+
interactionAuthMetricObserver,
|
|
15
|
+
interactionInterventionMetricObserver,
|
|
16
|
+
interactionOperationMetricObserver,
|
|
17
|
+
type Observability,
|
|
18
|
+
} from "@opengeni/observability";
|
|
19
|
+
|
|
20
|
+
type InteractionActionReceipt = BrowserActionReceipt | ComputerActionReceipt;
|
|
21
|
+
type InteractionLifecycleMutation =
|
|
22
|
+
| BrowserSessionMutationResponse
|
|
23
|
+
| ComputerSessionMutationResponse;
|
|
24
|
+
type AuthMutation = AuthRunMutationResponse | ProtectedAuthFillResponse;
|
|
25
|
+
|
|
26
|
+
const STALE_INTERACTION_ERROR_CODES = new Set([
|
|
27
|
+
"controller_stale",
|
|
28
|
+
"target_stale",
|
|
29
|
+
"observation_stale",
|
|
30
|
+
"document_stale",
|
|
31
|
+
"frame_stale",
|
|
32
|
+
"attempt_stale",
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
export function observeBrowserActionResult(
|
|
36
|
+
observability: Observability | null | undefined,
|
|
37
|
+
startedAtMs: number,
|
|
38
|
+
request: BrowserActionRequest,
|
|
39
|
+
receipt: BrowserActionReceipt,
|
|
40
|
+
): void {
|
|
41
|
+
interactionOperationMetricObserver(observability)({
|
|
42
|
+
resource: "browser",
|
|
43
|
+
operation: "act",
|
|
44
|
+
mode: browserActionMode(request.action),
|
|
45
|
+
outcome: actionReceiptOutcome(receipt),
|
|
46
|
+
durationMs: elapsedMs(startedAtMs),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function observeComputerActionResult(
|
|
51
|
+
observability: Observability | null | undefined,
|
|
52
|
+
startedAtMs: number,
|
|
53
|
+
request: ComputerActionRequest,
|
|
54
|
+
receipt: ComputerActionReceipt,
|
|
55
|
+
): void {
|
|
56
|
+
interactionOperationMetricObserver(observability)({
|
|
57
|
+
resource: "computer",
|
|
58
|
+
operation: "act",
|
|
59
|
+
mode: computerActionMode(request.action.type),
|
|
60
|
+
outcome: actionReceiptOutcome(receipt),
|
|
61
|
+
durationMs: elapsedMs(startedAtMs),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function observeLifecycleResult(
|
|
66
|
+
observability: Observability | null | undefined,
|
|
67
|
+
startedAtMs: number,
|
|
68
|
+
response: InteractionLifecycleMutation,
|
|
69
|
+
): void {
|
|
70
|
+
interactionOperationMetricObserver(observability)({
|
|
71
|
+
resource: response.operation.resourceKind === "browser_session" ? "browser" : "computer",
|
|
72
|
+
operation: response.operation.kind,
|
|
73
|
+
mode: "lifecycle",
|
|
74
|
+
outcome: actionReceiptOutcome(response.operation),
|
|
75
|
+
durationMs: elapsedMs(startedAtMs),
|
|
76
|
+
replayed: response.operation.replayed,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function observeBrowserRevisionPublication(
|
|
81
|
+
observability: Observability | null | undefined,
|
|
82
|
+
startedAtMs: number,
|
|
83
|
+
response: PublishBrowserRevisionResponse,
|
|
84
|
+
): void {
|
|
85
|
+
interactionOperationMetricObserver(observability)({
|
|
86
|
+
resource: "browser",
|
|
87
|
+
operation: "publish",
|
|
88
|
+
mode: "lifecycle",
|
|
89
|
+
outcome: "completed",
|
|
90
|
+
durationMs: elapsedMs(startedAtMs),
|
|
91
|
+
replayed: response.replayed,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function observeAuthMutation(
|
|
96
|
+
observability: Observability | null | undefined,
|
|
97
|
+
startedAtMs: number,
|
|
98
|
+
response: AuthMutation,
|
|
99
|
+
): void {
|
|
100
|
+
interactionAuthMetricObserver(observability)({
|
|
101
|
+
state: response.run.state,
|
|
102
|
+
durationMs: elapsedMs(startedAtMs),
|
|
103
|
+
replayed: response.replayed,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function observeInterventionMutation(
|
|
108
|
+
observability: Observability | null | undefined,
|
|
109
|
+
response: InteractionInterventionMutationResponse,
|
|
110
|
+
): void {
|
|
111
|
+
const { intervention } = response;
|
|
112
|
+
interactionInterventionMetricObserver(observability)({
|
|
113
|
+
kind: intervention.kind,
|
|
114
|
+
outcome: intervention.status === "open" ? "opened" : intervention.status,
|
|
115
|
+
...(intervention.settledAt
|
|
116
|
+
? {
|
|
117
|
+
waitMs: Math.max(
|
|
118
|
+
0,
|
|
119
|
+
Date.parse(intervention.settledAt) - Date.parse(intervention.createdAt),
|
|
120
|
+
),
|
|
121
|
+
}
|
|
122
|
+
: {}),
|
|
123
|
+
replayed: response.replayed,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function browserActionMode(action: BrowserActionRequest["action"]): string {
|
|
128
|
+
const actions = action.type === "batch" ? action.actions : [action];
|
|
129
|
+
if (actions.some((candidate) => candidate.type === "pointer")) return "coordinate";
|
|
130
|
+
if (actions.some((candidate) => candidate.type === "type" || candidate.type === "press")) {
|
|
131
|
+
return "keyboard";
|
|
132
|
+
}
|
|
133
|
+
if (actions.some((candidate) => candidate.type === "clipboard")) return "clipboard";
|
|
134
|
+
if (actions.some((candidate) => candidate.type === "permission")) return "permission";
|
|
135
|
+
return "semantic";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function computerActionMode(type: ComputerActionRequest["action"]["type"]): string {
|
|
139
|
+
if (type === "pointer") return "coordinate";
|
|
140
|
+
if (type === "keyboard") return "keyboard";
|
|
141
|
+
if (type === "clipboard") return "clipboard";
|
|
142
|
+
if (type === "launch") return "lifecycle";
|
|
143
|
+
return "semantic";
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function actionReceiptOutcome(receipt: Pick<InteractionActionReceipt, "state" | "error">): string {
|
|
147
|
+
if (
|
|
148
|
+
receipt.state === "failed" &&
|
|
149
|
+
receipt.error &&
|
|
150
|
+
STALE_INTERACTION_ERROR_CODES.has(receipt.error.code)
|
|
151
|
+
) {
|
|
152
|
+
return "stale";
|
|
153
|
+
}
|
|
154
|
+
return receipt.state;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function elapsedMs(startedAtMs: number): number {
|
|
158
|
+
return Math.max(0, performance.now() - startedAtMs);
|
|
159
|
+
}
|
package/src/mcp/documents.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import { DocumentSearchResponse, ListIndexedDocumentsResponse } from "@opengeni/contracts";
|
|
2
1
|
import {
|
|
2
|
+
KNOWLEDGE_BROWSE_CURSOR_MAX_CHARS,
|
|
3
|
+
KnowledgeBrowseResponse,
|
|
4
|
+
KnowledgeGetResponse,
|
|
5
|
+
KnowledgeRecordId,
|
|
6
|
+
KnowledgeSearchResponse,
|
|
7
|
+
ListIndexedDocumentsResponse,
|
|
8
|
+
} from "@opengeni/contracts";
|
|
9
|
+
import {
|
|
10
|
+
browseEffectiveKnowledge,
|
|
11
|
+
getEffectiveKnowledgeRecord,
|
|
3
12
|
getDocumentChunk,
|
|
4
13
|
listDocumentBases,
|
|
5
14
|
listEffectiveIndexedDocuments,
|
|
15
|
+
searchEffectiveKnowledge,
|
|
6
16
|
searchEffectiveDocuments,
|
|
7
17
|
type DocumentAccessFilter,
|
|
8
18
|
type DocumentServices,
|
|
@@ -91,7 +101,6 @@ export function buildDocumentsMcpServer(
|
|
|
91
101
|
documentServices,
|
|
92
102
|
input,
|
|
93
103
|
options.initiatingSubjectId,
|
|
94
|
-
false,
|
|
95
104
|
),
|
|
96
105
|
);
|
|
97
106
|
|
|
@@ -103,17 +112,80 @@ export function buildDocumentsMcpServer(
|
|
|
103
112
|
inputSchema: SearchInputSchema,
|
|
104
113
|
},
|
|
105
114
|
async (input) =>
|
|
106
|
-
|
|
115
|
+
searchKnowledge(
|
|
107
116
|
db,
|
|
108
117
|
accountId,
|
|
109
118
|
workspaceId,
|
|
110
119
|
documentServices,
|
|
111
120
|
input,
|
|
112
121
|
options.initiatingSubjectId,
|
|
113
|
-
true,
|
|
114
122
|
),
|
|
115
123
|
);
|
|
116
124
|
|
|
125
|
+
server.registerTool(
|
|
126
|
+
"knowledge_get",
|
|
127
|
+
{
|
|
128
|
+
description:
|
|
129
|
+
"Fetch one stable Knowledge record by the id returned from knowledge_search or knowledge_browse. Authorization and agent access are rechecked before content or links are returned.",
|
|
130
|
+
inputSchema: { id: KnowledgeRecordId },
|
|
131
|
+
},
|
|
132
|
+
async ({ id }) => {
|
|
133
|
+
const record = await getEffectiveKnowledgeRecord(db, {
|
|
134
|
+
accountId,
|
|
135
|
+
workspaceId,
|
|
136
|
+
initiatingSubjectId: options.initiatingSubjectId,
|
|
137
|
+
id,
|
|
138
|
+
});
|
|
139
|
+
return {
|
|
140
|
+
content: [
|
|
141
|
+
{
|
|
142
|
+
type: "text",
|
|
143
|
+
text: record
|
|
144
|
+
? JSON.stringify(KnowledgeGetResponse.parse({ record }))
|
|
145
|
+
: `knowledge record not found: ${id}`,
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
isError: !record,
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
server.registerTool(
|
|
154
|
+
"knowledge_browse",
|
|
155
|
+
{
|
|
156
|
+
description:
|
|
157
|
+
"Browse authorized Knowledge without crawling folders. Omit parentId to list source documents; pass a document record id to inspect its chunks. Opaque cursors are bound to this user, workspace, parent, and filters.",
|
|
158
|
+
inputSchema: {
|
|
159
|
+
parentId: KnowledgeRecordId.optional(),
|
|
160
|
+
topic: z.string().min(1).max(256).optional(),
|
|
161
|
+
sourceKinds: SearchInputSchema.sourceKinds,
|
|
162
|
+
cursor: z.string().min(1).max(KNOWLEDGE_BROWSE_CURSOR_MAX_CHARS).optional(),
|
|
163
|
+
limit: z.number().int().positive().max(50).optional(),
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
async ({ parentId, topic, sourceKinds, cursor, limit }) => ({
|
|
167
|
+
content: [
|
|
168
|
+
{
|
|
169
|
+
type: "text",
|
|
170
|
+
text: JSON.stringify(
|
|
171
|
+
KnowledgeBrowseResponse.parse(
|
|
172
|
+
await browseEffectiveKnowledge(db, {
|
|
173
|
+
accountId,
|
|
174
|
+
workspaceId,
|
|
175
|
+
initiatingSubjectId: options.initiatingSubjectId,
|
|
176
|
+
...(parentId ? { parentId } : {}),
|
|
177
|
+
...(topic ? { topic } : {}),
|
|
178
|
+
...(sourceKinds ? { sourceKinds } : {}),
|
|
179
|
+
...(cursor ? { cursor } : {}),
|
|
180
|
+
...(limit ? { limit } : {}),
|
|
181
|
+
}),
|
|
182
|
+
),
|
|
183
|
+
),
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
|
|
117
189
|
server.registerTool(
|
|
118
190
|
"list_indexed_documents",
|
|
119
191
|
{
|
|
@@ -295,7 +367,6 @@ async function searchContent(
|
|
|
295
367
|
aclTags?: string[] | undefined;
|
|
296
368
|
},
|
|
297
369
|
initiatingSubjectId: string,
|
|
298
|
-
wrapResponse: boolean,
|
|
299
370
|
) {
|
|
300
371
|
const results = await searchEffectiveDocuments(
|
|
301
372
|
db,
|
|
@@ -317,8 +388,46 @@ async function searchContent(
|
|
|
317
388
|
content: [
|
|
318
389
|
{
|
|
319
390
|
type: "text" as const,
|
|
320
|
-
text: JSON.stringify(
|
|
391
|
+
text: JSON.stringify(results),
|
|
321
392
|
},
|
|
322
393
|
],
|
|
323
394
|
};
|
|
324
395
|
}
|
|
396
|
+
|
|
397
|
+
async function searchKnowledge(
|
|
398
|
+
db: Database,
|
|
399
|
+
accountId: string,
|
|
400
|
+
workspaceId: string,
|
|
401
|
+
documentServices: DocumentServices,
|
|
402
|
+
input: {
|
|
403
|
+
query: string;
|
|
404
|
+
baseIds?: string[] | undefined;
|
|
405
|
+
limit?: number | undefined;
|
|
406
|
+
mode?: "hybrid" | "vector" | "keyword" | undefined;
|
|
407
|
+
sourceKinds?: Parameters<typeof searchContent>[4]["sourceKinds"];
|
|
408
|
+
aclTags?: string[] | undefined;
|
|
409
|
+
},
|
|
410
|
+
initiatingSubjectId: string,
|
|
411
|
+
) {
|
|
412
|
+
const response = await searchEffectiveKnowledge(
|
|
413
|
+
db,
|
|
414
|
+
{
|
|
415
|
+
accountId,
|
|
416
|
+
workspaceId,
|
|
417
|
+
query: input.query,
|
|
418
|
+
...(input.baseIds ? { baseIds: input.baseIds } : {}),
|
|
419
|
+
...(input.limit ? { limit: input.limit } : {}),
|
|
420
|
+
...(input.mode ? { mode: input.mode } : {}),
|
|
421
|
+
...(input.sourceKinds ? { sourceKinds: input.sourceKinds } : {}),
|
|
422
|
+
...(input.aclTags ? { aclTags: input.aclTags } : {}),
|
|
423
|
+
initiatingSubjectId,
|
|
424
|
+
surface: "agent",
|
|
425
|
+
},
|
|
426
|
+
documentServices,
|
|
427
|
+
);
|
|
428
|
+
return {
|
|
429
|
+
content: [
|
|
430
|
+
{ type: "text" as const, text: JSON.stringify(KnowledgeSearchResponse.parse(response)) },
|
|
431
|
+
],
|
|
432
|
+
};
|
|
433
|
+
}
|