This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-7190-91a036bf4f78d862b5f63b0360bcb5d769b6d2bb in repository https://gitbox.apache.org/repos/asf/texera.git
commit 050c226a6e9c605c1a9c6ae8adae9920af053def Author: Xinyuan Lin <[email protected]> AuthorDate: Fri Jul 31 22:34:44 2026 -0700 test(agent-service): cover prompt composition (#7190) ### What changes were proposed in this PR? Adds isolated unit coverage for agent system-prompt composition from workflow metadata. The tests exercise allowlist filtering, language-specific UDF guidance, the default all-operator path, and the missing-operator fallback. ### Any related issues, documentation, discussions? Closes #7187 ### How was this PR tested? - `bun test src/agent/prompts.spec.ts` — 4 passed. - `bun run typecheck` - `bunx prettier --check "src/**/*.{ts,js,json}"` Mutation proof (each production change was reverted): | Production mutation | Focused test result | | --- | --- | | Inverted non-empty allowlist selection | 3 failed | | Omitted operator descriptions | 1 failed | | Changed the no-operators fallback message | 1 failed | ### Was this PR authored or co-authored using generative AI tooling? Generated-by: Codex (GPT-5) --------- Signed-off-by: Xinyuan Lin <[email protected]> Co-authored-by: Copilot Autofix powered by AI <[email protected]> --- agent-service/src/agent/prompts.spec.ts | 99 +++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/agent-service/src/agent/prompts.spec.ts b/agent-service/src/agent/prompts.spec.ts new file mode 100644 index 0000000000..d4ae6e2151 --- /dev/null +++ b/agent-service/src/agent/prompts.spec.ts @@ -0,0 +1,99 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { describe, expect, test } from "bun:test"; +import type { OperatorSchema } from "../api/backend-api"; +import { buildSystemPrompt } from "./prompts"; +import { WorkflowSystemMetadata } from "./util/workflow-system-metadata"; + +function makeOperatorSchema(operatorType: string, description: string): OperatorSchema { + return { + operatorType, + operatorVersion: "1.0", + jsonSchema: { + properties: { + condition: { type: "string" }, + }, + required: ["condition"], + }, + additionalMetadata: { + userFriendlyName: operatorType, + operatorGroupName: "Test", + operatorDescription: description, + inputPorts: [], + outputPorts: [], + }, + }; +} + +function makeMetadataStore(): WorkflowSystemMetadata { + const metadataStore = new WorkflowSystemMetadata(); + metadataStore.loadFromMetadata({ + operators: [ + makeOperatorSchema("Filter", "Keeps rows that match a condition."), + makeOperatorSchema("PythonUDFV2", "Runs user-defined Python code."), + makeOperatorSchema("RUDF", "Runs user-defined R code."), + ], + groups: [], + }); + return metadataStore; +} + +describe("buildSystemPrompt", () => { + test("renders only explicitly allowed operators with their descriptions and compact schemas", () => { + const prompt = buildSystemPrompt(makeMetadataStore(), ["Filter"]); + + expect(prompt).toContain("## Filter"); + expect(prompt).toContain("Description: Keeps rows that match a condition."); + expect(prompt).toMatch(/"condition":\s*\{\s*"type":\s*"string"/); + expect(prompt).not.toContain("## PythonUDFV2"); + expect(prompt).not.toContain("## RUDF"); + expect(prompt).not.toContain("## Python UDF Guide"); + expect(prompt).not.toContain("## R UDF Guide"); + }); + + test("adds guidance only for the UDF language in a restricted allowlist", () => { + const metadataStore = makeMetadataStore(); + const pythonPrompt = buildSystemPrompt(metadataStore, ["PythonUDFV2"]); + const rPrompt = buildSystemPrompt(metadataStore, ["RUDF"]); + + expect(pythonPrompt).toContain("## Python UDF Guide"); + expect(pythonPrompt).not.toContain("## R UDF Guide"); + expect(rPrompt).toContain("## R UDF Guide"); + expect(rPrompt).not.toContain("## Python UDF Guide"); + }); + + test("uses all metadata operators and both UDF guides when no allowlist is supplied", () => { + const prompt = buildSystemPrompt(makeMetadataStore()); + + expect(prompt).toContain("## Filter"); + expect(prompt).toContain("## PythonUDFV2"); + expect(prompt).toContain("## RUDF"); + expect(prompt).toContain("## Python UDF Guide"); + expect(prompt).toContain("## R UDF Guide"); + }); + + test("reports that no operators are available when a restricted type is absent from metadata", () => { + const prompt = buildSystemPrompt(makeMetadataStore(), ["MissingOperator"]); + + expect(prompt).toContain("No operators available."); + expect(prompt).not.toContain("## Python UDF Guide"); + expect(prompt).not.toContain("## R UDF Guide"); + }); +});
