Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changeset/tools-schema-precompile-typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@executor-js/sdk": minor
"@executor-js/plugin-semantic-search": patch
Comment thread
aryasaatvik marked this conversation as resolved.
Resolved
---

Always render the TypeScript preview in `executor.tools.schema` and warm it during
indexing. The `includeTypeScript` option (and the now-empty `ToolSchemaOptions` type) is
removed — the only caller that passed `false` was the reindex pipeline, which did so to
skip the CPU-heavy JSON-schema → TypeScript codegen. It now calls `tools.schema` plainly,
so every reindex pre-warms exactly the schema view the web UI reads on first open (the
codegen is content-addressed in KV), turning first tool-detail views into cache hits
instead of a cold compile. The embedding text is unchanged — the indexer only ever read
the raw schema facets, never the rendered TypeScript. Because `includeTypeScript` is
dropped from the schema-view cache key, existing cached entries are superseded on the next
reindex or view (regenerable derived data).
2 changes: 1 addition & 1 deletion packages/core/sdk/src/executor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ describe("createExecutor", () => {
expect(inspect?.definitionSetHash).toHaveLength(64);
expect(inspect?.indexFingerprint).toHaveLength(64);

const schema = yield* executor.tools.schema(addr("inspect"), { includeTypeScript: false });
const schema = yield* executor.tools.schema(addr("inspect"));
expect(schema?.schemaDefinitions).not.toHaveProperty("Unused");
}),
);
Expand Down
57 changes: 20 additions & 37 deletions packages/core/sdk/src/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,7 @@ import {
ORG_SUBJECT,
type ExecutorOwnerPolicyContext,
} from "./owner-policy";
import {
ToolSchemaManifest,
ToolSchemaView,
type IntegrationDetectionResult,
type ToolSchemaOptions,
} from "./types";
import { ToolSchemaManifest, ToolSchemaView, type IntegrationDetectionResult } from "./types";
import { type Tool, type ToolAnnotations, type ToolDef, type ToolListFilter } from "./tool";
import { buildToolTypeScriptPreview, type ToolTypeScriptPreview } from "./schema-types";
import { collectReferencedDefinitions } from "./schema-refs";
Expand Down Expand Up @@ -329,10 +324,7 @@ export type Executor<TPlugins extends readonly AnyPlugin[] = readonly []> = {
readonly manifest: (
filter?: ToolListFilter,
) => Effect.Effect<readonly ToolSchemaManifest[], StorageFailure>;
readonly schema: (
address: ToolAddress,
options?: ToolSchemaOptions,
) => Effect.Effect<ToolSchemaView | null, StorageFailure>;
readonly schema: (address: ToolAddress) => Effect.Effect<ToolSchemaView | null, StorageFailure>;
};

readonly providers: {
Expand Down Expand Up @@ -3216,14 +3208,12 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea

const toolSchema = (
address: ToolAddress,
options?: ToolSchemaOptions,
): Effect.Effect<ToolSchemaView | null, StorageFailure> =>
Effect.gen(function* () {
// The JSON-schema → TypeScript codegen is the CPU-heavy part of this
// surface; callers that only need the schema's content (a reindex
// computing a content fingerprint) opt out and skip it. Raw schema roots
// + referenced `$defs` are returned either way.
const includeTypeScript = options?.includeTypeScript ?? true;
// Always renders the JSON-schema → TypeScript preview. The codegen is the
// CPU-heavy part of this surface, but the rendered view is content-addressed
// in KV, so the reindex pipeline warms exactly the view the web UI reads on
// first open. Raw schema roots + referenced `$defs` are returned alongside.
const staticEntry = staticTools.get(String(address));
if (staticEntry) {
const tool = staticToolToTool(staticEntry);
Expand All @@ -3234,22 +3224,19 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
inputSchema: tool.inputSchema,
outputSchema: tool.outputSchema,
definitions: {},
includeTypeScript,
});
const cached = yield* toolSchemaViewStore
.get(key)
.pipe(Effect.catch(() => Effect.succeed(Option.none())));
if (Option.isSome(cached)) return cached.value.view;

const preview = includeTypeScript
? Option.getOrUndefined(
yield* buildCachedToolTypeScriptPreview({
inputSchema: tool.inputSchema,
outputSchema: tool.outputSchema,
defs: new Map(),
}).pipe(Effect.option),
)
: undefined;
const preview = Option.getOrUndefined(
yield* buildCachedToolTypeScriptPreview({
inputSchema: tool.inputSchema,
outputSchema: tool.outputSchema,
defs: new Map(),
}).pipe(Effect.option),
);
const view = ToolSchemaView.make({
address,
name: tool.name,
Expand Down Expand Up @@ -3290,7 +3277,6 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
address: String(address),
indexFingerprint: manifest.indexFingerprint,
fingerprintVersion: manifest.fingerprintVersion,
includeTypeScript,
});
if (manifestCacheKey !== null) {
const cached = yield* toolSchemaViewStore
Expand Down Expand Up @@ -3331,7 +3317,6 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
inputSchema: tool.inputSchema,
outputSchema: tool.outputSchema,
definitions,
includeTypeScript,
}));
if (manifestCacheKey === null) {
const cached = yield* toolSchemaViewStore
Expand All @@ -3345,15 +3330,13 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea
defs,
);
const referencedDefs = new Map<string, unknown>(Object.entries(referenced));
const preview = includeTypeScript
? Option.getOrUndefined(
yield* buildCachedToolTypeScriptPreview({
inputSchema: tool.inputSchema,
outputSchema: tool.outputSchema,
defs: referencedDefs,
}).pipe(Effect.option),
)
: undefined;
const preview = Option.getOrUndefined(
yield* buildCachedToolTypeScriptPreview({
inputSchema: tool.inputSchema,
outputSchema: tool.outputSchema,
defs: referencedDefs,
}).pipe(Effect.option),
);

const view = ToolSchemaView.make({
address,
Expand Down
1 change: 0 additions & 1 deletion packages/core/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ export type { CredentialProvider, ProviderEntry } from "./provider";

// Public projections / detection.
export { ToolSchemaManifest, ToolSchemaView, IntegrationDetectionResult } from "./types";
export type { ToolSchemaOptions } from "./types";

// Core schema.
export {
Expand Down
1 change: 0 additions & 1 deletion packages/core/sdk/src/promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export type {
UpdateToolPolicyInput,
} from "./policies";
export { ToolSchemaManifest, ToolSchemaView, IntegrationDetectionResult } from "./types";
export type { ToolSchemaOptions } from "./types";
export type { Tool, ToolDef, ToolListFilter, ToolAnnotations } from "./tool";
export type { AnyPlugin, PluginExtensions } from "./plugin";
export type {
Expand Down
1 change: 0 additions & 1 deletion packages/core/sdk/src/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export type { ToolPolicyAction } from "./core-schema";

// Schema-side views + onboarding autodetect.
export { ToolSchemaManifest, ToolSchemaView, IntegrationDetectionResult } from "./types";
export type { ToolSchemaOptions } from "./types";

// OAuth wire contracts (data + tagged errors; the flow impl is server-only).
export {
Expand Down
3 changes: 0 additions & 3 deletions packages/core/sdk/src/tool-schema-view-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ describe("toolSchemaViewCacheKey", () => {
inputSchema: { type: "object", properties: { pet: { type: "string" } } },
}),
).not.toBe(sameKey);
expect(yield* toolSchemaViewCacheKey({ ...base, includeTypeScript: false })).not.toBe(
sameKey,
);
}),
);
});
4 changes: 0 additions & 4 deletions packages/core/sdk/src/tool-schema-view-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,12 @@ interface ToolSchemaViewCacheKeyInput {
readonly inputSchema?: unknown;
readonly outputSchema?: unknown;
readonly definitions: Readonly<Record<string, unknown>>;
readonly includeTypeScript?: boolean;
}

interface ToolSchemaViewManifestCacheKeyInput {
readonly address: string;
readonly indexFingerprint: string;
readonly fingerprintVersion: string;
readonly includeTypeScript?: boolean;
}

const cachePayload = (input: ToolSchemaViewCacheKeyInput): string =>
Expand All @@ -46,7 +44,6 @@ const cachePayload = (input: ToolSchemaViewCacheKeyInput): string =>
inputSchema: input.inputSchema,
outputSchema: input.outputSchema,
definitions: input.definitions,
includeTypeScript: input.includeTypeScript ?? true,
});

const manifestCachePayload = (input: ToolSchemaViewManifestCacheKeyInput): string =>
Expand All @@ -57,7 +54,6 @@ const manifestCachePayload = (input: ToolSchemaViewManifestCacheKeyInput): strin
address: input.address,
indexFingerprint: input.indexFingerprint,
fingerprintVersion: input.fingerprintVersion,
includeTypeScript: input.includeTypeScript ?? true,
});

export const toolSchemaViewCacheKey = (input: ToolSchemaViewCacheKeyInput): Effect.Effect<string> =>
Expand Down
12 changes: 0 additions & 12 deletions packages/core/sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,6 @@ export const ToolSchemaManifest = Schema.Struct({
});
export type ToolSchemaManifest = typeof ToolSchemaManifest.Type;

/** Options for `executor.tools.schema`. */
export interface ToolSchemaOptions {
/** Generate the TypeScript preview strings (`inputTypeScript` /
* `outputTypeScript` / `typeScriptDefinitions`). Defaults to `true`. Pass
* `false` to skip the CPU-heavy JSON-schema → TypeScript codegen and return
* only the raw JSON schema roots plus referenced `$defs` — the cheap tier for
* callers that need the schema's content but not its rendered types (e.g. a
* reindex computing a content fingerprint). Mirrors `tools.list`'s
* `includeAnnotations` opt-out of an expensive per-tool derivation. */
readonly includeTypeScript?: boolean;
}

// ---------------------------------------------------------------------------
// Integration detection — optional capability on `PluginSpec.detect`. When a
// user pastes a URL in the onboarding UI, `executor.integrations.detect(url)`
Expand Down
10 changes: 6 additions & 4 deletions packages/plugins/semantic-search/src/sdk/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export const listToolDescriptors = (
*
* This is the manifest tier for indexing: it carries precomputed raw-schema
* fingerprints from source refresh, so scan/diff can avoid per-tool
* `tools.schema(includeTypeScript: false)` reads entirely. */
* `tools.schema` reads entirely. */
export const listToolManifests = (
executor: Executor,
options?: ListToolDescriptorsOptions,
Expand Down Expand Up @@ -219,8 +219,10 @@ const schemaDefinitionsFacetText = (

/** Collect `ToolDocumentInput` for a single tool descriptor.
*
* Attempts to fetch raw schema via `tools.schema(address, { includeTypeScript:
* false })` to populate compact schema facets; on failure it degrades
* Fetches the tool's schema via `tools.schema(address)` to populate compact
* schema facets from the raw input/output schema + `$defs`. The TypeScript
* preview it also renders is unused here, but the call warms the shared
* schema-view cache the web UI reads on first open. On failure it degrades
* gracefully to an identity-only document.
*/
export const collectDocForTool = (
Expand All @@ -234,7 +236,7 @@ export const collectDocForTool = (
integration: String(tool.integration),
description: stripHtml(String(tool.description ?? "")),
};
return executor.tools.schema(tool.address as Tool["address"], { includeTypeScript: false }).pipe(
return executor.tools.schema(tool.address as Tool["address"]).pipe(
Effect.map((view): ToolDocumentInput => {
if (view === null) return { ...base, lexicalText: buildLexicalText(base) };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,12 @@ const makeExecutor = (
tools: {
list: () => Effect.succeed([tool]),
manifest: () => Effect.succeed([manifestForTool(tool)]),
schema: (address, options) => {
const includeTypeScript = options?.includeTypeScript ?? true;
if (includeTypeScript) counters.codegen++;
else counters.raw++;
schema: (address) => {
counters.codegen++;
return Effect.succeed({
address,
inputSchema: { type: "object", properties: { owner: { type: "string" } } },
inputTypeScript: includeTypeScript ? "{ owner: string }" : undefined,
inputTypeScript: "{ owner: string }",
});
},
},
Expand Down Expand Up @@ -298,7 +296,7 @@ describe("ToolSearchIndex", () => {
expect(chunked.processed).toBe(1);
expect(chunked.chunks).toBeGreaterThan(0);
expect(embedded).toMatchObject({ processed: chunked.chunks, chunks: chunked.chunks });
expect(counters).toEqual({ raw: 1, codegen: 0 });
expect(counters).toEqual({ raw: 0, codegen: 1 });
expect(upserted).toHaveLength(chunked.chunks);
for (const vector of upserted) {
expect(
Expand Down Expand Up @@ -478,7 +476,7 @@ describe("ToolSearchIndex", () => {
expect(first.chunkRefs.length).toBeGreaterThan(0);
expect(retry.chunkRefs).toEqual(first.chunkRefs);
expect(retry.commitPaths).toEqual([]);
expect(counters).toEqual({ raw: 1, codegen: 0 });
expect(counters).toEqual({ raw: 0, codegen: 1 });
}),
);

Expand Down
Loading