mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-24 23:54:13 +08:00
Compare commits
11 Commits
v1.0.18
...
inigo/stru
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
606f6af1c6 | ||
|
|
6bc261bb35 | ||
|
|
84265a4271 | ||
|
|
9d3bab5bc7 | ||
|
|
bf8f85ca9d | ||
|
|
f551cdf070 | ||
|
|
ec3a934da7 | ||
|
|
8cd2cc1236 | ||
|
|
dcee434ef2 | ||
|
|
e93583852d | ||
|
|
e600a516c7 |
72
.github/workflows/test-structured-output.yml
vendored
72
.github/workflows/test-structured-output.yml
vendored
@@ -30,10 +30,19 @@ jobs:
|
|||||||
- number_field: 42
|
- number_field: 42
|
||||||
- boolean_true: true
|
- boolean_true: true
|
||||||
- boolean_false: false
|
- boolean_false: false
|
||||||
|
json_schema: |
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"text_field": {"type": "string"},
|
||||||
|
"number_field": {"type": "number"},
|
||||||
|
"boolean_true": {"type": "boolean"},
|
||||||
|
"boolean_false": {"type": "boolean"}
|
||||||
|
},
|
||||||
|
"required": ["text_field", "number_field", "boolean_true", "boolean_false"]
|
||||||
|
}
|
||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
claude_args: |
|
claude_args: "--allowedTools Bash"
|
||||||
--allowedTools Bash
|
|
||||||
--json-schema '{"type":"object","properties":{"text_field":{"type":"string"},"number_field":{"type":"number"},"boolean_true":{"type":"boolean"},"boolean_false":{"type":"boolean"}},"required":["text_field","number_field","boolean_true","boolean_false"]}'
|
|
||||||
|
|
||||||
- name: Verify outputs
|
- name: Verify outputs
|
||||||
run: |
|
run: |
|
||||||
@@ -88,10 +97,21 @@ jobs:
|
|||||||
- items: ["apple", "banana", "cherry"]
|
- items: ["apple", "banana", "cherry"]
|
||||||
- config: {"key": "value", "count": 3}
|
- config: {"key": "value", "count": 3}
|
||||||
- empty_array: []
|
- empty_array: []
|
||||||
|
json_schema: |
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "string"}
|
||||||
|
},
|
||||||
|
"config": {"type": "object"},
|
||||||
|
"empty_array": {"type": "array"}
|
||||||
|
},
|
||||||
|
"required": ["items", "config", "empty_array"]
|
||||||
|
}
|
||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
claude_args: |
|
claude_args: "--allowedTools Bash"
|
||||||
--allowedTools Bash
|
|
||||||
--json-schema '{"type":"object","properties":{"items":{"type":"array","items":{"type":"string"}},"config":{"type":"object"},"empty_array":{"type":"array"}},"required":["items","config","empty_array"]}'
|
|
||||||
|
|
||||||
- name: Verify JSON stringification
|
- name: Verify JSON stringification
|
||||||
run: |
|
run: |
|
||||||
@@ -140,10 +160,19 @@ jobs:
|
|||||||
- empty_string: ""
|
- empty_string: ""
|
||||||
- negative: -5
|
- negative: -5
|
||||||
- decimal: 3.14
|
- decimal: 3.14
|
||||||
|
json_schema: |
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"zero": {"type": "number"},
|
||||||
|
"empty_string": {"type": "string"},
|
||||||
|
"negative": {"type": "number"},
|
||||||
|
"decimal": {"type": "number"}
|
||||||
|
},
|
||||||
|
"required": ["zero", "empty_string", "negative", "decimal"]
|
||||||
|
}
|
||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
claude_args: |
|
claude_args: "--allowedTools Bash"
|
||||||
--allowedTools Bash
|
|
||||||
--json-schema '{"type":"object","properties":{"zero":{"type":"number"},"empty_string":{"type":"string"},"negative":{"type":"number"},"decimal":{"type":"number"}},"required":["zero","empty_string","negative","decimal"]}'
|
|
||||||
|
|
||||||
- name: Verify edge cases
|
- name: Verify edge cases
|
||||||
run: |
|
run: |
|
||||||
@@ -194,10 +223,17 @@ jobs:
|
|||||||
prompt: |
|
prompt: |
|
||||||
Run: echo "test"
|
Run: echo "test"
|
||||||
Return EXACTLY: {test-result: "passed", item_count: 10}
|
Return EXACTLY: {test-result: "passed", item_count: 10}
|
||||||
|
json_schema: |
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"test-result": {"type": "string"},
|
||||||
|
"item_count": {"type": "number"}
|
||||||
|
},
|
||||||
|
"required": ["test-result", "item_count"]
|
||||||
|
}
|
||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
claude_args: |
|
claude_args: "--allowedTools Bash"
|
||||||
--allowedTools Bash
|
|
||||||
--json-schema '{"type":"object","properties":{"test-result":{"type":"string"},"item_count":{"type":"number"}},"required":["test-result","item_count"]}'
|
|
||||||
|
|
||||||
- name: Verify sanitized names work
|
- name: Verify sanitized names work
|
||||||
run: |
|
run: |
|
||||||
@@ -232,10 +268,16 @@ jobs:
|
|||||||
uses: ./base-action
|
uses: ./base-action
|
||||||
with:
|
with:
|
||||||
prompt: "Run: echo 'complete'. Return: {done: true}"
|
prompt: "Run: echo 'complete'. Return: {done: true}"
|
||||||
|
json_schema: |
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"done": {"type": "boolean"}
|
||||||
|
},
|
||||||
|
"required": ["done"]
|
||||||
|
}
|
||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
claude_args: |
|
claude_args: "--allowedTools Bash"
|
||||||
--allowedTools Bash
|
|
||||||
--json-schema '{"type":"object","properties":{"done":{"type":"boolean"}},"required":["done"]}'
|
|
||||||
|
|
||||||
- name: Verify execution file contains structured_output
|
- name: Verify execution file contains structured_output
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
10
action.yml
10
action.yml
@@ -113,6 +113,10 @@ inputs:
|
|||||||
description: "Newline-separated list of Claude Code plugin marketplace Git URLs to install from (e.g., 'https://github.com/user/marketplace1.git\nhttps://github.com/user/marketplace2.git')"
|
description: "Newline-separated list of Claude Code plugin marketplace Git URLs to install from (e.g., 'https://github.com/user/marketplace1.git\nhttps://github.com/user/marketplace2.git')"
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
|
json_schema:
|
||||||
|
description: "JSON schema for structured output validation. When provided, Claude will return validated JSON matching this schema. All fields are available in the structured_output output as a JSON string (use fromJSON() or jq to access fields)."
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
execution_file:
|
execution_file:
|
||||||
@@ -125,7 +129,7 @@ outputs:
|
|||||||
description: "The GitHub token used by the action (Claude App token if available)"
|
description: "The GitHub token used by the action (Claude App token if available)"
|
||||||
value: ${{ steps.prepare.outputs.github_token }}
|
value: ${{ steps.prepare.outputs.github_token }}
|
||||||
structured_output:
|
structured_output:
|
||||||
description: "JSON string containing all structured output fields when --json-schema is provided in claude_args. Use fromJSON() to parse: fromJSON(steps.id.outputs.structured_output).field_name"
|
description: "JSON string containing all structured output fields when json_schema input is provided. Use fromJSON() to parse: fromJSON(steps.id.outputs.structured_output).field_name"
|
||||||
value: ${{ steps.claude-code.outputs.structured_output }}
|
value: ${{ steps.claude-code.outputs.structured_output }}
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
@@ -177,6 +181,7 @@ runs:
|
|||||||
TRACK_PROGRESS: ${{ inputs.track_progress }}
|
TRACK_PROGRESS: ${{ inputs.track_progress }}
|
||||||
ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }}
|
ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }}
|
||||||
CLAUDE_ARGS: ${{ inputs.claude_args }}
|
CLAUDE_ARGS: ${{ inputs.claude_args }}
|
||||||
|
JSON_SCHEMA: ${{ inputs.json_schema }}
|
||||||
ALL_INPUTS: ${{ toJson(inputs) }}
|
ALL_INPUTS: ${{ toJson(inputs) }}
|
||||||
|
|
||||||
- name: Install Base Action Dependencies
|
- name: Install Base Action Dependencies
|
||||||
@@ -192,7 +197,7 @@ runs:
|
|||||||
# Install Claude Code if no custom executable is provided
|
# Install Claude Code if no custom executable is provided
|
||||||
if [ -z "${{ inputs.path_to_claude_code_executable }}" ]; then
|
if [ -z "${{ inputs.path_to_claude_code_executable }}" ]; then
|
||||||
echo "Installing Claude Code..."
|
echo "Installing Claude Code..."
|
||||||
curl -fsSL https://claude.ai/install.sh | bash -s 2.0.45
|
curl -fsSL https://claude.ai/install.sh | bash -s 2.0.42
|
||||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||||
else
|
else
|
||||||
echo "Using custom Claude Code executable: ${{ inputs.path_to_claude_code_executable }}"
|
echo "Using custom Claude Code executable: ${{ inputs.path_to_claude_code_executable }}"
|
||||||
@@ -231,6 +236,7 @@ runs:
|
|||||||
INPUT_SHOW_FULL_OUTPUT: ${{ inputs.show_full_output }}
|
INPUT_SHOW_FULL_OUTPUT: ${{ inputs.show_full_output }}
|
||||||
INPUT_PLUGINS: ${{ inputs.plugins }}
|
INPUT_PLUGINS: ${{ inputs.plugins }}
|
||||||
INPUT_PLUGIN_MARKETPLACES: ${{ inputs.plugin_marketplaces }}
|
INPUT_PLUGIN_MARKETPLACES: ${{ inputs.plugin_marketplaces }}
|
||||||
|
JSON_SCHEMA: ${{ inputs.json_schema }}
|
||||||
|
|
||||||
# Model configuration
|
# Model configuration
|
||||||
GITHUB_TOKEN: ${{ steps.prepare.outputs.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ steps.prepare.outputs.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -67,6 +67,14 @@ inputs:
|
|||||||
description: "Newline-separated list of Claude Code plugin marketplace Git URLs to install from (e.g., 'https://github.com/user/marketplace1.git\nhttps://github.com/user/marketplace2.git')"
|
description: "Newline-separated list of Claude Code plugin marketplace Git URLs to install from (e.g., 'https://github.com/user/marketplace1.git\nhttps://github.com/user/marketplace2.git')"
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
|
json_schema:
|
||||||
|
description: |
|
||||||
|
JSON schema for structured output validation. Claude must return JSON matching this schema
|
||||||
|
or the action will fail. All fields are returned in a single structured_output JSON string.
|
||||||
|
|
||||||
|
Access outputs via: fromJSON(steps.<step-id>.outputs.structured_output).<field_name>
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
conclusion:
|
conclusion:
|
||||||
@@ -76,7 +84,7 @@ outputs:
|
|||||||
description: "Path to the JSON file containing Claude Code execution log"
|
description: "Path to the JSON file containing Claude Code execution log"
|
||||||
value: ${{ steps.run_claude.outputs.execution_file }}
|
value: ${{ steps.run_claude.outputs.execution_file }}
|
||||||
structured_output:
|
structured_output:
|
||||||
description: "JSON string containing all structured output fields when --json-schema is provided in claude_args (use fromJSON() or jq to parse)"
|
description: "JSON string containing all structured output fields (use fromJSON() or jq to parse)"
|
||||||
value: ${{ steps.run_claude.outputs.structured_output }}
|
value: ${{ steps.run_claude.outputs.structured_output }}
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
@@ -144,6 +152,7 @@ runs:
|
|||||||
INPUT_SHOW_FULL_OUTPUT: ${{ inputs.show_full_output }}
|
INPUT_SHOW_FULL_OUTPUT: ${{ inputs.show_full_output }}
|
||||||
INPUT_PLUGINS: ${{ inputs.plugins }}
|
INPUT_PLUGINS: ${{ inputs.plugins }}
|
||||||
INPUT_PLUGIN_MARKETPLACES: ${{ inputs.plugin_marketplaces }}
|
INPUT_PLUGIN_MARKETPLACES: ${{ inputs.plugin_marketplaces }}
|
||||||
|
JSON_SCHEMA: ${{ inputs.json_schema }}
|
||||||
|
|
||||||
# Provider configuration
|
# Provider configuration
|
||||||
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
|
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
|
||||||
|
|||||||
@@ -28,8 +28,22 @@ async function run() {
|
|||||||
promptFile: process.env.INPUT_PROMPT_FILE || "",
|
promptFile: process.env.INPUT_PROMPT_FILE || "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Build claudeArgs with JSON schema if provided
|
||||||
|
let claudeArgs = process.env.INPUT_CLAUDE_ARGS || "";
|
||||||
|
|
||||||
|
// Add allowed tools if specified
|
||||||
|
if (process.env.INPUT_ALLOWED_TOOLS) {
|
||||||
|
claudeArgs += ` --allowedTools "${process.env.INPUT_ALLOWED_TOOLS}"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add JSON schema if specified (no escaping - parseShellArgs handles it)
|
||||||
|
if (process.env.JSON_SCHEMA) {
|
||||||
|
// Wrap in single quotes for parseShellArgs
|
||||||
|
claudeArgs += ` --json-schema '${process.env.JSON_SCHEMA}'`;
|
||||||
|
}
|
||||||
|
|
||||||
await runClaude(promptConfig.path, {
|
await runClaude(promptConfig.path, {
|
||||||
claudeArgs: process.env.INPUT_CLAUDE_ARGS,
|
claudeArgs: claudeArgs.trim(),
|
||||||
allowedTools: process.env.INPUT_ALLOWED_TOOLS,
|
allowedTools: process.env.INPUT_ALLOWED_TOOLS,
|
||||||
disallowedTools: process.env.INPUT_DISALLOWED_TOOLS,
|
disallowedTools: process.env.INPUT_DISALLOWED_TOOLS,
|
||||||
maxTurns: process.env.INPUT_MAX_TURNS,
|
maxTurns: process.env.INPUT_MAX_TURNS,
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export function prepareRunConfig(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses structured_output from execution file and sets GitHub Action outputs
|
* Parses structured_output from execution file and sets GitHub Action outputs
|
||||||
* Only runs if --json-schema was explicitly provided in claude_args
|
* Only runs if json_schema was explicitly provided by the user
|
||||||
* Exported for testing
|
* Exported for testing
|
||||||
*/
|
*/
|
||||||
export async function parseAndSetStructuredOutputs(
|
export async function parseAndSetStructuredOutputs(
|
||||||
@@ -144,7 +144,7 @@ export async function parseAndSetStructuredOutputs(
|
|||||||
|
|
||||||
if (!result?.structured_output) {
|
if (!result?.structured_output) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`--json-schema was provided but Claude did not return structured_output.\n` +
|
`json_schema was provided but Claude did not return structured_output.\n` +
|
||||||
`Found ${messages.length} messages. Result exists: ${!!result}\n`,
|
`Found ${messages.length} messages. Result exists: ${!!result}\n`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -167,9 +167,6 @@ export async function parseAndSetStructuredOutputs(
|
|||||||
export async function runClaude(promptPath: string, options: ClaudeOptions) {
|
export async function runClaude(promptPath: string, options: ClaudeOptions) {
|
||||||
const config = prepareRunConfig(promptPath, options);
|
const config = prepareRunConfig(promptPath, options);
|
||||||
|
|
||||||
// Detect if --json-schema is present in claude args
|
|
||||||
const hasJsonSchema = options.claudeArgs?.includes("--json-schema") ?? false;
|
|
||||||
|
|
||||||
// Create a named pipe
|
// Create a named pipe
|
||||||
try {
|
try {
|
||||||
await unlink(PIPE_PATH);
|
await unlink(PIPE_PATH);
|
||||||
@@ -355,8 +352,8 @@ export async function runClaude(promptPath: string, options: ClaudeOptions) {
|
|||||||
|
|
||||||
core.setOutput("execution_file", EXECUTION_FILE);
|
core.setOutput("execution_file", EXECUTION_FILE);
|
||||||
|
|
||||||
// Parse and set structured outputs only if user provided --json-schema in claude_args
|
// Parse and set structured outputs only if user provided json_schema
|
||||||
if (hasJsonSchema) {
|
if (process.env.JSON_SCHEMA) {
|
||||||
try {
|
try {
|
||||||
await parseAndSetStructuredOutputs(EXECUTION_FILE);
|
await parseAndSetStructuredOutputs(EXECUTION_FILE);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ describe("parseAndSetStructuredOutputs", () => {
|
|||||||
await expect(
|
await expect(
|
||||||
parseAndSetStructuredOutputs(TEST_EXECUTION_FILE),
|
parseAndSetStructuredOutputs(TEST_EXECUTION_FILE),
|
||||||
).rejects.toThrow(
|
).rejects.toThrow(
|
||||||
"--json-schema was provided but Claude did not return structured_output",
|
"json_schema was provided but Claude did not return structured_output",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ describe("parseAndSetStructuredOutputs", () => {
|
|||||||
await expect(
|
await expect(
|
||||||
parseAndSetStructuredOutputs(TEST_EXECUTION_FILE),
|
parseAndSetStructuredOutputs(TEST_EXECUTION_FILE),
|
||||||
).rejects.toThrow(
|
).rejects.toThrow(
|
||||||
"--json-schema was provided but Claude did not return structured_output",
|
"json_schema was provided but Claude did not return structured_output",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ jobs:
|
|||||||
| `path_to_bun_executable` | Optional path to a custom Bun executable. Skips automatic Bun installation. Useful for Nix, custom containers, or specialized environments | No | "" |
|
| `path_to_bun_executable` | Optional path to a custom Bun executable. Skips automatic Bun installation. Useful for Nix, custom containers, or specialized environments | No | "" |
|
||||||
| `plugin_marketplaces` | Newline-separated list of Claude Code plugin marketplace Git URLs to install from (e.g., see example in workflow above). Marketplaces are added before plugin installation | No | "" |
|
| `plugin_marketplaces` | Newline-separated list of Claude Code plugin marketplace Git URLs to install from (e.g., see example in workflow above). Marketplaces are added before plugin installation | No | "" |
|
||||||
| `plugins` | Newline-separated list of Claude Code plugin names to install (e.g., see example in workflow above). Plugins are installed before Claude Code execution | No | "" |
|
| `plugins` | Newline-separated list of Claude Code plugin names to install (e.g., see example in workflow above). Plugins are installed before Claude Code execution | No | "" |
|
||||||
|
| `json_schema` | JSON schema for structured output validation. See [Structured Outputs](#structured-outputs) section below | No | "" |
|
||||||
|
|
||||||
### Deprecated Inputs
|
### Deprecated Inputs
|
||||||
|
|
||||||
@@ -200,8 +201,16 @@ Get validated JSON results from Claude that automatically become GitHub Action o
|
|||||||
prompt: |
|
prompt: |
|
||||||
Check the CI logs and determine if this is a flaky test.
|
Check the CI logs and determine if this is a flaky test.
|
||||||
Return: is_flaky (boolean), confidence (0-1), summary (string)
|
Return: is_flaky (boolean), confidence (0-1), summary (string)
|
||||||
claude_args: |
|
json_schema: |
|
||||||
--json-schema '{"type":"object","properties":{"is_flaky":{"type":"boolean"},"confidence":{"type":"number"},"summary":{"type":"string"}},"required":["is_flaky"]}'
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"is_flaky": {"type": "boolean"},
|
||||||
|
"confidence": {"type": "number"},
|
||||||
|
"summary": {"type": "string"}
|
||||||
|
},
|
||||||
|
"required": ["is_flaky"]
|
||||||
|
}
|
||||||
|
|
||||||
- name: Retry if flaky
|
- name: Retry if flaky
|
||||||
if: fromJSON(steps.analyze.outputs.structured_output).is_flaky == true
|
if: fromJSON(steps.analyze.outputs.structured_output).is_flaky == true
|
||||||
@@ -210,7 +219,7 @@ Get validated JSON results from Claude that automatically become GitHub Action o
|
|||||||
|
|
||||||
### How It Works
|
### How It Works
|
||||||
|
|
||||||
1. **Define Schema**: Provide a JSON schema via `--json-schema` flag in `claude_args`
|
1. **Define Schema**: Provide a JSON schema in the `json_schema` input
|
||||||
2. **Claude Executes**: Claude uses tools to complete your task
|
2. **Claude Executes**: Claude uses tools to complete your task
|
||||||
3. **Validated Output**: Result is validated against your schema
|
3. **Validated Output**: Result is validated against your schema
|
||||||
4. **JSON Output**: All fields are returned in a single `structured_output` JSON string
|
4. **JSON Output**: All fields are returned in a single `structured_output` JSON string
|
||||||
|
|||||||
@@ -43,8 +43,27 @@ jobs:
|
|||||||
- is_flaky: true if likely flaky, false if real bug
|
- is_flaky: true if likely flaky, false if real bug
|
||||||
- confidence: number 0-1 indicating confidence level
|
- confidence: number 0-1 indicating confidence level
|
||||||
- summary: brief one-sentence explanation
|
- summary: brief one-sentence explanation
|
||||||
claude_args: |
|
json_schema: |
|
||||||
--json-schema '{"type":"object","properties":{"is_flaky":{"type":"boolean","description":"Whether this appears to be a flaky test failure"},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Confidence level in the determination"},"summary":{"type":"string","description":"One-sentence explanation of the failure"}},"required":["is_flaky","confidence","summary"]}'
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"is_flaky": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether this appears to be a flaky test failure"
|
||||||
|
},
|
||||||
|
"confidence": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 1,
|
||||||
|
"description": "Confidence level in the determination"
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "One-sentence explanation of the failure"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["is_flaky", "confidence", "summary"]
|
||||||
|
}
|
||||||
|
|
||||||
# Auto-retry only if flaky AND high confidence (>= 0.7)
|
# Auto-retry only if flaky AND high confidence (>= 0.7)
|
||||||
- name: Retry flaky tests
|
- name: Retry flaky tests
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { parseAllowedTools } from "./parse-tools";
|
|||||||
import { configureGitAuth } from "../../github/operations/git-config";
|
import { configureGitAuth } from "../../github/operations/git-config";
|
||||||
import type { GitHubContext } from "../../github/context";
|
import type { GitHubContext } from "../../github/context";
|
||||||
import { isEntityContext } from "../../github/context";
|
import { isEntityContext } from "../../github/context";
|
||||||
|
import { appendJsonSchemaArg } from "../../utils/json-schema";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract GitHub context as environment variables for agent mode
|
* Extract GitHub context as environment variables for agent mode
|
||||||
@@ -149,6 +150,9 @@ export const agentMode: Mode = {
|
|||||||
claudeArgs = `--mcp-config '${escapedOurConfig}'`;
|
claudeArgs = `--mcp-config '${escapedOurConfig}'`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add JSON schema if provided
|
||||||
|
claudeArgs = appendJsonSchemaArg(claudeArgs);
|
||||||
|
|
||||||
// Append user's claude_args (which may have more --mcp-config flags)
|
// Append user's claude_args (which may have more --mcp-config flags)
|
||||||
claudeArgs = `${claudeArgs} ${userClaudeArgs}`.trim();
|
claudeArgs = `${claudeArgs} ${userClaudeArgs}`.trim();
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { isEntityContext } from "../../github/context";
|
|||||||
import type { PreparedContext } from "../../create-prompt/types";
|
import type { PreparedContext } from "../../create-prompt/types";
|
||||||
import type { FetchDataResult } from "../../github/data/fetcher";
|
import type { FetchDataResult } from "../../github/data/fetcher";
|
||||||
import { parseAllowedTools } from "../agent/parse-tools";
|
import { parseAllowedTools } from "../agent/parse-tools";
|
||||||
|
import { appendJsonSchemaArg } from "../../utils/json-schema";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag mode implementation.
|
* Tag mode implementation.
|
||||||
@@ -177,6 +178,9 @@ export const tagMode: Mode = {
|
|||||||
// Add required tools for tag mode
|
// Add required tools for tag mode
|
||||||
claudeArgs += ` --allowedTools "${tagModeTools.join(",")}"`;
|
claudeArgs += ` --allowedTools "${tagModeTools.join(",")}"`;
|
||||||
|
|
||||||
|
// Add JSON schema if provided
|
||||||
|
claudeArgs = appendJsonSchemaArg(claudeArgs);
|
||||||
|
|
||||||
// Append user's claude_args (which may have more --mcp-config flags)
|
// Append user's claude_args (which may have more --mcp-config flags)
|
||||||
if (userClaudeArgs) {
|
if (userClaudeArgs) {
|
||||||
claudeArgs += ` ${userClaudeArgs}`;
|
claudeArgs += ` ${userClaudeArgs}`;
|
||||||
|
|||||||
17
src/utils/json-schema.ts
Normal file
17
src/utils/json-schema.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Appends JSON schema CLI argument if json_schema is provided
|
||||||
|
* Escapes schema for safe shell passing
|
||||||
|
*/
|
||||||
|
export function appendJsonSchemaArg(
|
||||||
|
claudeArgs: string,
|
||||||
|
jsonSchemaStr?: string,
|
||||||
|
): string {
|
||||||
|
const schema = jsonSchemaStr || process.env.JSON_SCHEMA || "";
|
||||||
|
if (!schema) {
|
||||||
|
return claudeArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLI validates schema - just escape for safe shell passing
|
||||||
|
const escapedSchema = schema.replace(/'/g, "'\\''");
|
||||||
|
return `${claudeArgs} --json-schema '${escapedSchema}'`;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user