History

Warm source index at startup

Rhys Sullivan committed 7 months ago

Commit 211e5c21 parent ee439d36 files · +342 −44Browse files

Unified · Split

6 files
  1. .changeset/cold-lions-listen.md +5 −0
  2. packages/platform/sdk/src/runtime/catalog/source/runtime.ts +150 −32
  3. packages/platform/sdk/src/runtime/execution/scope/source-catalog.test.ts +80 −0
  4. packages/platform/sdk/src/runtime/execution/scope/source-catalog.ts +41 −12
  5. packages/platform/sdk/src/runtime/index.test.ts +46 −0
  6. packages/platform/sdk/src/runtime/index.ts +20 −0
.changeset/cold-lions-listen.md+5−0
@@ -0,0 +1,5 @@
1---
2"executor": patch
3---
4
5Prewarm the lean workspace source index at startup and reuse it across discovery requests so the first tool search no longer pays the full catalog hydration cost.
packages/platform/sdk/src/runtime/catalog/source/runtime.ts+150−32
@@ -8,6 +8,7 @@ import type { · 7 unmodified lines
8 StoredSourceRecord,8 StoredSourceRecord,
9 StoredSourceCatalogRevisionRecord,9 StoredSourceCatalogRevisionRecord,
10} from "#schema";10} from "#schema";
11import * as Cache from "effect/Cache";
11import * as Context from "effect/Context";12import * as Context from "effect/Context";
12import * as Effect from "effect/Effect";13import * as Effect from "effect/Effect";
13import * as Layer from "effect/Layer";14import * as Layer from "effect/Layer";
@@ -133,6 +134,22 @@ const catalogNamespaceFromPath = (path: string): string => { · 119 unmodified lines
133 134
134const descriptorPath = (descriptor: CatalogToolDescriptor): string => descriptor.path;135const descriptorPath = (descriptor: CatalogToolDescriptor): string => descriptor.path;
135 136
137export const loadedSourceCatalogToolIndexEntryFromLoadedTool = (
138 tool: LoadedSourceCatalogTool,
139): LoadedSourceCatalogToolIndexEntry => ({
140 path: tool.path,
141 searchNamespace: tool.searchNamespace,
142 searchText: tool.searchText,
143 source: tool.source,
144 sourceRecord: tool.sourceRecord,
145 capabilityId: tool.capabilityId,
146 executableId: tool.executableId,
147 capability: tool.capability,
148 executable: tool.executable,
149 descriptor: tool.descriptor,
150 projectedCatalog: tool.projectedCatalog,
151});
152
136const optionalJsonString = (value: unknown): string | null => {153const optionalJsonString = (value: unknown): string | null => {
137 if (value === undefined || value === null) {154 if (value === undefined || value === null) {
138 return null;155 return null;
@@ -683,7 +700,6 @@ type RuntimeSourceCatalogStoreShape = { · 544 unmodified lines
683 loadWorkspaceSourceCatalogToolIndex: (input: {700 loadWorkspaceSourceCatalogToolIndex: (input: {
684 scopeId: ScopeId;701 scopeId: ScopeId;
685 actorScopeId?: ScopeId | null;702 actorScopeId?: ScopeId | null;
686 includeSchemas: boolean;
687 }) => Effect.Effect<readonly LoadedSourceCatalogToolIndexEntry[], Error, never>;703 }) => Effect.Effect<readonly LoadedSourceCatalogToolIndexEntry[], Error, never>;
688 loadWorkspaceSourceCatalogToolByPath: (input: {704 loadWorkspaceSourceCatalogToolByPath: (input: {
689 scopeId: ScopeId;705 scopeId: ScopeId;
@@ -710,6 +726,23 @@ type SourceCatalogRuntimeServices = · 20 unmodified lines
710 | RuntimeSourceStoreService726 | RuntimeSourceStoreService
711 | SourceArtifactStore;727 | SourceArtifactStore;
712 728
729type WorkspaceSourceCatalogCacheKey = {
730 scopeId: ScopeId;
731 actorScopeId: ScopeId | null;
732 sourceFingerprint: string;
733};
734
735const normalizeActorScopeId = (
736 actorScopeId?: ScopeId | null,
737): ScopeId | null => actorScopeId ?? null;
738
739const workspaceSourceFingerprint = (sources: readonly Source[]): string =>
740 JSON.stringify(
741 [...sources].sort((left, right) =>
742 String(left.id).localeCompare(String(right.id))
743 ),
744 );
745
713const ensureRuntimeCatalogWorkspace = (746const ensureRuntimeCatalogWorkspace = (
714 deps: RuntimeSourceCatalogStoreDeps,747 deps: RuntimeSourceCatalogStoreDeps,
715 scopeId: ScopeId,748 scopeId: ScopeId,
@@ -731,19 +764,45 @@ const buildSnapshotFromArtifact = (input: { · 15 unmodified lines
731 return decodeCatalogSnapshotV1(input.artifact.snapshot);764 return decodeCatalogSnapshotV1(input.artifact.snapshot);
732};765};
733 766
734const loadWorkspaceSourceCatalogsWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: {767const loadWorkspaceSourcesWithDeps = (
735 scopeId: ScopeId;768 deps: RuntimeSourceCatalogStoreDeps,
736 actorScopeId?: ScopeId | null;769 input: {
737}): Effect.Effect<readonly LoadedSourceCatalog[], Error, never> =>770 scopeId: ScopeId;
771 actorScopeId?: ScopeId | null;
772 },
773): Effect.Effect<readonly Source[], Error, never> =>
738 Effect.gen(function* () {774 Effect.gen(function* () {
739 yield* ensureRuntimeCatalogWorkspace(deps, input.scopeId);775 yield* ensureRuntimeCatalogWorkspace(deps, input.scopeId);
740 const sources = yield* deps.sourceStore.loadSourcesInScope(776
777 return yield* deps.sourceStore.loadSourcesInScope(
741 input.scopeId,778 input.scopeId,
742 {779 {
743 actorScopeId: input.actorScopeId,780 actorScopeId: input.actorScopeId,
744 },781 },
745 );782 );
783 });
746 784
785const loadWorkspaceSourceCatalogCacheKeyWithDeps = (
786 deps: RuntimeSourceCatalogStoreDeps,
787 input: {
788 scopeId: ScopeId;
789 actorScopeId?: ScopeId | null;
790 },
791): Effect.Effect<WorkspaceSourceCatalogCacheKey, Error, never> =>
792 Effect.map(
793 loadWorkspaceSourcesWithDeps(deps, input),
794 (sources) => ({
795 scopeId: input.scopeId,
796 actorScopeId: normalizeActorScopeId(input.actorScopeId),
797 sourceFingerprint: workspaceSourceFingerprint(sources),
798 }),
799 );
800
801const loadLoadedSourceCatalogsFromSourcesWithDeps = (
802 deps: RuntimeSourceCatalogStoreDeps,
803 sources: readonly Source[],
804): Effect.Effect<readonly LoadedSourceCatalog[], Error, never> =>
805 Effect.gen(function* () {
747 const localCatalogs = yield* Effect.forEach(sources, (source) =>806 const localCatalogs = yield* Effect.forEach(sources, (source) =>
748 Effect.gen(function* () {807 Effect.gen(function* () {
749 const artifact = yield* deps.sourceArtifactStore.read({808 const artifact = yield* deps.sourceArtifactStore.read({
@@ -781,6 +840,15 @@ const loadWorkspaceSourceCatalogsWithDeps = (deps: RuntimeSourceCatalogStoreDeps · 31 unmodified lines
781 return localCatalogs.filter((catalogEntry): catalogEntry is LoadedSourceCatalog => catalogEntry !== null);840 return localCatalogs.filter((catalogEntry): catalogEntry is LoadedSourceCatalog => catalogEntry !== null);
782 });841 });
783 842
843const loadWorkspaceSourceCatalogsWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: {
844 scopeId: ScopeId;
845 actorScopeId?: ScopeId | null;
846}): Effect.Effect<readonly LoadedSourceCatalog[], Error, never> =>
847 Effect.gen(function* () {
848 const sources = yield* loadWorkspaceSourcesWithDeps(deps, input);
849 return yield* loadLoadedSourceCatalogsFromSourcesWithDeps(deps, sources);
850 });
851
784const loadSourceWithCatalogWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: {852const loadSourceWithCatalogWithDeps = (deps: RuntimeSourceCatalogStoreDeps, input: {
785 scopeId: ScopeId;853 scopeId: ScopeId;
786 sourceId: Source["id"];854 sourceId: Source["id"];
@@ -1107,7 +1175,6 @@ export const expandCatalogToolByPath = (input: { · 320 unmodified lines
1107export const loadWorkspaceSourceCatalogToolIndex = (input: {1175export const loadWorkspaceSourceCatalogToolIndex = (input: {
1108 scopeId: ScopeId;1176 scopeId: ScopeId;
1109 actorScopeId?: ScopeId | null;1177 actorScopeId?: ScopeId | null;
1110 includeSchemas: boolean;
1111}): Effect.Effect<1178}): Effect.Effect<
1112 readonly LoadedSourceCatalogToolIndexEntry[],1179 readonly LoadedSourceCatalogToolIndexEntry[],
1113 Error,1180 Error,
@@ -1120,21 +1187,10 @@ export const loadWorkspaceSourceCatalogToolIndex = (input: { · 6 unmodified lines
1120 });1187 });
1121 const tools = yield* expandCatalogTools({1188 const tools = yield* expandCatalogTools({
1122 catalogs,1189 catalogs,
1123 includeSchemas: input.includeSchemas,1190 includeSchemas: false,
1191 includeTypePreviews: false,
1124 });1192 });
1125 return tools.map((tool) => ({1193 return tools.map(loadedSourceCatalogToolIndexEntryFromLoadedTool);
1126 path: tool.path,
1127 searchNamespace: tool.searchNamespace,
1128 searchText: tool.searchText,
1129 source: tool.source,
1130 sourceRecord: tool.sourceRecord,
1131 capabilityId: tool.capabilityId,
1132 executableId: tool.executableId,
1133 capability: tool.capability,
1134 executable: tool.executable,
1135 descriptor: tool.descriptor,
1136 projectedCatalog: tool.projectedCatalog,
1137 }));
1138 });1194 });
1139 1195
1140export const loadWorkspaceSourceCatalogToolByPath = (input: {1196export const loadWorkspaceSourceCatalogToolByPath = (input: {
@@ -1187,23 +1243,85 @@ export const RuntimeSourceCatalogStoreLive = Layer.effect( · 46 unmodified lines
1187 sourceArtifactStore,1243 sourceArtifactStore,
1188 };1244 };
1189 1245
1246 const workspaceCatalogCache = yield* Cache.make<
1247 WorkspaceSourceCatalogCacheKey,
1248 readonly LoadedSourceCatalog[],
1249 Error
1250 >({
1251 capacity: 32,
1252 timeToLive: "10 minutes",
1253 lookup: (key) =>
1254 loadWorkspaceSourceCatalogsWithDeps(
1255 deps,
1256 {
1257 scopeId: key.scopeId,
1258 actorScopeId: key.actorScopeId,
1259 },
1260 ),
1261 });
1262
1263 const leanWorkspaceToolIndexCache = yield* Cache.make<
1264 WorkspaceSourceCatalogCacheKey,
1265 readonly LoadedSourceCatalogToolIndexEntry[],
1266 Error
1267 >({
1268 capacity: 32,
1269 timeToLive: "10 minutes",
1270 lookup: (key) =>
1271 Effect.gen(function* () {
1272 const catalogs = yield* workspaceCatalogCache.get(key);
1273 const tools = yield* expandCatalogTools({
1274 catalogs,
1275 includeSchemas: false,
1276 includeTypePreviews: false,
1277 });
1278
1279 return tools.map(loadedSourceCatalogToolIndexEntryFromLoadedTool);
1280 }),
1281 });
1282
1283 const loadCachedWorkspaceCatalogs = (input: {
1284 scopeId: ScopeId;
1285 actorScopeId?: ScopeId | null;
1286 }) =>
1287 Effect.flatMap(
1288 loadWorkspaceSourceCatalogCacheKeyWithDeps(deps, input),
1289 (key) => workspaceCatalogCache.get(key),
1290 );
1291
1292 const loadLeanWorkspaceToolIndex = (input: {
1293 scopeId: ScopeId;
1294 actorScopeId?: ScopeId | null;
1295 }) =>
1296 Effect.flatMap(
1297 loadWorkspaceSourceCatalogCacheKeyWithDeps(deps, input),
1298 (key) => leanWorkspaceToolIndexCache.get(key),
1299 );
1300
1190 return RuntimeSourceCatalogStoreService.of({1301 return RuntimeSourceCatalogStoreService.of({
1191 loadWorkspaceSourceCatalogs: (input) =>1302 loadWorkspaceSourceCatalogs: (input) =>
1192 loadWorkspaceSourceCatalogsWithDeps(deps, input),1303 loadCachedWorkspaceCatalogs(input),
1193 loadSourceWithCatalog: (input) =>1304 loadSourceWithCatalog: (input) =>
1194 loadSourceWithCatalogWithDeps(deps, input),1305 loadSourceWithCatalogWithDeps(deps, input),
1195 loadWorkspaceSourceCatalogToolIndex: (input) =>1306 loadWorkspaceSourceCatalogToolIndex: (input) =>
1196 loadWorkspaceSourceCatalogToolIndex(input).pipe(1307 loadLeanWorkspaceToolIndex({
1197 Effect.provideService(RuntimeLocalScopeService, runtimeLocalScope),1308 scopeId: input.scopeId,
1198 Effect.provideService(RuntimeSourceStoreService, sourceStore),1309 actorScopeId: input.actorScopeId,
1199 Effect.provideService(SourceArtifactStore, sourceArtifactStore),1310 }),
1200 ),
1201 loadWorkspaceSourceCatalogToolByPath: (input) =>1311 loadWorkspaceSourceCatalogToolByPath: (input) =>
1202 loadWorkspaceSourceCatalogToolByPath(input).pipe(1312 input.includeSchemas
1203 Effect.provideService(RuntimeLocalScopeService, runtimeLocalScope),1313 ? loadWorkspaceSourceCatalogToolByPath(input).pipe(
1204 Effect.provideService(RuntimeSourceStoreService, sourceStore),1314 Effect.provideService(RuntimeLocalScopeService, runtimeLocalScope),
1205 Effect.provideService(SourceArtifactStore, sourceArtifactStore),1315 Effect.provideService(RuntimeSourceStoreService, sourceStore),
1206 ),1316 Effect.provideService(SourceArtifactStore, sourceArtifactStore),
1317 )
1318 : Effect.map(
1319 loadLeanWorkspaceToolIndex({
1320 scopeId: input.scopeId,
1321 actorScopeId: input.actorScopeId,
1322 }),
1323 (tools) => tools.find((tool) => tool.path === input.path) ?? null,
1324 ),
1207 });1325 });
1208 }),1326 }),
1209);1327);
packages/platform/sdk/src/runtime/execution/scope/source-catalog.test.ts+80−0
@@ -124,4 +124,84 @@ describe("scope source catalog", () => { · 123 unmodified lines
124 },124 },
125 ]);125 ]);
126 }));126 }));
127
128 it.effect("reuses a lean shared catalog for repeated no-schema search and lookup calls", () =>
129 Effect.gen(function* () {
130 const loadWorkspaceSourceCatalogToolIndexCalls: Array<undefined> = [];
131
132 const catalog = createScopeSourceCatalog({
133 scopeId: "ws_test" as any,
134 actorScopeId: "acc_test" as any,
135 sourceCatalogStore: {
136 loadWorkspaceSourceCatalogs: () => Effect.die("unexpected catalog load"),
137 loadWorkspaceSourceCatalogToolIndex: () => {
138 loadWorkspaceSourceCatalogToolIndexCalls.push(undefined);
139
140 return Effect.succeed([{
141 path: "github.issues.list",
142 searchNamespace: "github.issues",
143 searchText: "github issues list repository issues",
144 source: {
145 enabled: true,
146 status: "connected",
147 },
148 sourceRecord: {},
149 capabilityId: "cap_1",
150 executableId: "exec_1",
151 capability: {
152 surface: {
153 title: "List Repository Issues",
154 summary: "List issues for a repository",
155 },
156 },
157 executable: {
158 display: {
159 leaf: "list",
160 operationId: "listRepositoryIssues",
161 pathTemplate: "/repos/{owner}/{repo}/issues",
162 },
163 },
164 descriptor: {
165 path: "github.issues.list",
166 sourceKey: "github",
167 description: "List issues for a repository",
168 interaction: "auto",
169 },
170 projectedCatalog: {},
171 }] as any);
172 },
173 loadWorkspaceSourceCatalogToolByPath: () => Effect.die("unexpected tool lookup"),
174 } as any,
175 scopeConfigStore: noopScopeConfigStore,
176 scopeStateStore: noopScopeStateStore,
177 sourceArtifactStore: noopSourceArtifactStore,
178 runtimeLocalScope: null,
179 });
180
181 const hits = yield* catalog.searchTools({
182 query: "GitHub list repository issues",
183 limit: 20,
184 });
185 const first = yield* catalog.getToolByPath({
186 path: "github.issues.list" as any,
187 includeSchemas: false,
188 });
189 const second = yield* catalog.getToolByPath({
190 path: "github.issues.list" as any,
191 includeSchemas: false,
192 });
193 const listed = yield* catalog.listTools({
194 query: "GitHub list repository issues",
195 limit: 20,
196 includeSchemas: false,
197 });
198
199 expect(hits).toHaveLength(1);
200 expect(hits[0]?.path).toBe("github.issues.list");
201 expect(hits[0]?.score).toBeGreaterThan(0);
202 expect(first?.contract?.inputTypePreview).toBeUndefined();
203 expect(second?.contract?.outputTypePreview).toBeUndefined();
204 expect(listed).toHaveLength(1);
205 expect(loadWorkspaceSourceCatalogToolIndexCalls).toHaveLength(1);
206 }));
127});207});
packages/platform/sdk/src/runtime/execution/scope/source-catalog.ts+41−12
@@ -13,6 +13,8 @@ import { · 12 unmodified lines
13 RuntimeSourceCatalogStoreService,13 RuntimeSourceCatalogStoreService,
14 type LoadedSourceCatalogToolIndexEntry,14 type LoadedSourceCatalogToolIndexEntry,
15 catalogToolCatalogEntry,15 catalogToolCatalogEntry,
16 expandCatalogTools,
17 loadedSourceCatalogToolIndexEntryFromLoadedTool,
16} from "../../catalog/source/runtime";18} from "../../catalog/source/runtime";
17import type {19import type {
18 RuntimeLocalScopeState,20 RuntimeLocalScopeState,
@@ -134,17 +136,34 @@ export const loadWorkspaceCatalogTools = (input: { · 115 unmodified lines
134 Error,136 Error,
135 ScopeStorageServices137 ScopeStorageServices
136> =>138> =>
137 Effect.map(139 input.includeSchemas
138 input.sourceCatalogStore.loadWorkspaceSourceCatalogToolIndex({140 ? Effect.gen(function* () {
139 scopeId: input.scopeId,141 const catalogs = yield* input.sourceCatalogStore.loadWorkspaceSourceCatalogs({
140 actorScopeId: input.actorScopeId,142 scopeId: input.scopeId,
141 includeSchemas: input.includeSchemas,143 actorScopeId: input.actorScopeId,
142 }),144 });
143 (tools) =>145 const tools = yield* expandCatalogTools({
144 tools.filter(146 catalogs,
145 (tool) => tool.source.enabled && tool.source.status === "connected",147 includeSchemas: true,
146 ),148 includeTypePreviews: true,
147 );149 });
150
151 return tools
152 .map(loadedSourceCatalogToolIndexEntryFromLoadedTool)
153 .filter(
154 (tool) => tool.source.enabled && tool.source.status === "connected",
155 );
156 })
157 : Effect.map(
158 input.sourceCatalogStore.loadWorkspaceSourceCatalogToolIndex({
159 scopeId: input.scopeId,
160 actorScopeId: input.actorScopeId,
161 }),
162 (tools) =>
163 tools.filter(
164 (tool) => tool.source.enabled && tool.source.status === "connected",
165 ),
166 );
148 167
149export const loadWorkspaceCatalogToolByPath = (input: {168export const loadWorkspaceCatalogToolByPath = (input: {
150 scopeId: Source["scopeId"];169 scopeId: Source["scopeId"];
@@ -313,7 +332,7 @@ export const createScopeSourceCatalog = (input: { · 162 unmodified lines
313 const provideWorkspaceStorage = <A, E, R>(effect: Effect.Effect<A, E, R>) =>332 const provideWorkspaceStorage = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
314 effect.pipe(Effect.provide(scopeStorageLayer));333 effect.pipe(Effect.provide(scopeStorageLayer));
315 334
316 const createSharedCatalog = (includeSchemas: boolean): Effect.Effect<ToolCatalog, Error, never> =>335 const buildSharedCatalog = (includeSchemas: boolean) =>
317 provideWorkspaceStorage(Effect.gen(function* () {336 provideWorkspaceStorage(Effect.gen(function* () {
318 const catalogTools = yield* loadWorkspaceCatalogTools({337 const catalogTools = yield* loadWorkspaceCatalogTools({
319 scopeId: input.scopeId,338 scopeId: input.scopeId,
@@ -332,6 +351,16 @@ export const createScopeSourceCatalog = (input: { · 12 unmodified lines
332 });351 });
333 }));352 }));
334 353
354 const leanSharedCatalog = Effect.runSync(
355 Effect.cached(buildSharedCatalog(false)),
356 );
357 const schemaSharedCatalog = Effect.runSync(
358 Effect.cached(buildSharedCatalog(true)),
359 );
360
361 const createSharedCatalog = (includeSchemas: boolean): Effect.Effect<ToolCatalog, Error, never> =>
362 includeSchemas ? schemaSharedCatalog : leanSharedCatalog;
363
335 return {364 return {
336 listNamespaces: ({ limit }) =>365 listNamespaces: ({ limit }) =>
337 provideRuntimeLocalScope(366 provideRuntimeLocalScope(
packages/platform/sdk/src/runtime/index.test.ts+46−0
@@ -0,0 +1,46 @@
1import {
2 describe,
3 expect,
4 it,
5} from "@effect/vitest";
6import * as Effect from "effect/Effect";
7
8import {
9 RuntimeSourceCatalogStoreService,
10} from "./catalog/source/runtime";
11import {
12 prewarmWorkspaceSourceCatalogToolIndex,
13} from "./index";
14
15describe("runtime startup prewarm", () => {
16 it.effect("warms the workspace source tool index for the active installation", () =>
17 Effect.gen(function* () {
18 const calls: Array<{
19 scopeId: string;
20 actorScopeId: string | null | undefined;
21 }> = [];
22
23 yield* prewarmWorkspaceSourceCatalogToolIndex({
24 scopeId: "ws_test" as any,
25 actorScopeId: "acc_test" as any,
26 }).pipe(
27 Effect.provideService(
28 RuntimeSourceCatalogStoreService,
29 RuntimeSourceCatalogStoreService.of({
30 loadWorkspaceSourceCatalogs: () => Effect.die("unexpected catalog load"),
31 loadSourceWithCatalog: () => Effect.die("unexpected source load"),
32 loadWorkspaceSourceCatalogToolIndex: (input) => {
33 calls.push(input as any);
34 return Effect.succeed([]);
35 },
36 loadWorkspaceSourceCatalogToolByPath: () => Effect.die("unexpected tool lookup"),
37 }),
38 ),
39 );
40
41 expect(calls).toEqual([{
42 scopeId: "ws_test",
43 actorScopeId: "acc_test",
44 }]);
45 }));
46});
packages/platform/sdk/src/runtime/index.ts+20−0
@@ -17,6 +17,7 @@ import { · 16 unmodified lines
17 RuntimeSourceAuthMaterialLive,17 RuntimeSourceAuthMaterialLive,
18} from "./auth/source-auth-material";18} from "./auth/source-auth-material";
19import {19import {
20 RuntimeSourceCatalogStoreService,
20 RuntimeSourceCatalogStoreLive,21 RuntimeSourceCatalogStoreLive,
21} from "./catalog/source/runtime";22} from "./catalog/source/runtime";
22import {23import {
@@ -223,6 +224,18 @@ export type RuntimeAuthStorageServices = { · 200 unmodified lines
223 sourceSessions: ExecutorStateStoreShape["sourceAuthSessions"];224 sourceSessions: ExecutorStateStoreShape["sourceAuthSessions"];
224};225};
225 226
227export const prewarmWorkspaceSourceCatalogToolIndex = (input: {
228 scopeId: LocalInstallation["scopeId"];
229 actorScopeId: LocalInstallation["actorScopeId"];
230}) =>
231 Effect.gen(function* () {
232 const sourceCatalogStore = yield* RuntimeSourceCatalogStoreService;
233 yield* sourceCatalogStore.loadWorkspaceSourceCatalogToolIndex({
234 scopeId: input.scopeId,
235 actorScopeId: input.actorScopeId,
236 });
237 });
238
226export type RuntimeSecretsStorageServices =239export type RuntimeSecretsStorageServices =
227 & ExecutorStateStoreShape["secretMaterials"]240 & ExecutorStateStoreShape["secretMaterials"]
228 & RuntimeSecretMaterialServices;241 & RuntimeSecretMaterialServices;
@@ -513,6 +526,13 @@ export const createExecutorRuntimeFromServices = (input: { · 284 unmodified lines
513 Effect.provide(managedRuntime),526 Effect.provide(managedRuntime),
514 Effect.catchAll(() => Effect.void),527 Effect.catchAll(() => Effect.void),
515 );528 );
529 yield* prewarmWorkspaceSourceCatalogToolIndex({
530 scopeId: localInstallation.scopeId,
531 actorScopeId: localInstallation.actorScopeId,
532 }).pipe(
533 Effect.provide(managedRuntime),
534 Effect.catchAll(() => Effect.void),
535 );
516 536
517 return {537 return {
518 storage: input.services.storage,538 storage: input.services.storage,