Skip to content

Add inline engine.driver sources for Copilot SDK workflows - #47991

Merged
pelikhan merged 9 commits into
mainfrom
copilot/extend-engine-driver-syntax
Jul 25, 2026
Merged

Add inline engine.driver sources for Copilot SDK workflows#47991
pelikhan merged 9 commits into
mainfrom
copilot/extend-engine-driver-syntax

Conversation

Copilot AI commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

This extends engine.driver so Copilot workflows can define the driver inline instead of committing a separate file. The compiler now materializes inline Node, Python, Go, or Java driver sources at runtime and wires the engine to execute them with the matching Copilot SDK setup.

  • New frontmatter shape

    • engine.driver now accepts either the existing string form or an inline object with exactly one runtime source:
      • node:
      • python:
      • go:
      • java:
    engine:
      id: copilot
      driver:
        python: |
          import sys
          print("hello from inline driver", file=sys.stderr)
  • Compiler support

    • Parse inline driver objects into engine config.
    • Validate runtime selection and reject inline drivers outside the Copilot engine.
    • Extend schema/docs so the new syntax is discoverable and editor-aware.
  • Runtime materialization

    • Generate driver source files under .gh-aw/copilot-sdk/.
    • Generate a wrapper launcher using the same runtime-oriented naming approach as mcp-scripts.
    • Point Copilot SDK driver execution at the generated wrapper rather than requiring a checked-in driver file.
  • SDK/runtime wiring

    • Detect the inline runtime and install the corresponding SDK/toolchain path:
      • Node / TypeScript via npm
      • Python via pip target dir
      • Go via module-local go get
      • Java via Maven classpath generation
    • Feed runtime detection so workflow setup includes the required host runtime automatically.
  • Copilot execution path

    • Preserve existing driver-mode behavior while allowing workspace-generated executable wrappers.
    • Keep language-specific env handling, including Python SDK path injection, working for inline drivers.

run: https://github.com/github/gh-aw/actions/runs/30159569186

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 10.8 AIC · ⌖ 8.79 AIC · ⊞ 7.1K ·
Comment /souschef to run again


Run: https://github.com/github/gh-aw/actions/runs/30160879503

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 3.29 AIC · ⌖ 8.12 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title Extend engine.driver to support inline Copilot SDK sources Add inline engine.driver sources for Copilot SDK workflows Jul 25, 2026
Copilot AI requested a review from pelikhan July 25, 2026 11:50
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot add integration workflow test

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot add integration workflow test

Addressed in 0650344. Added an integration test that compiles a Copilot workflow with an inline Python engine.driver and verifies runtime setup, driver materialization, SDK install, and wrapper execution wiring in the generated agent job.

@pelikhan
pelikhan marked this pull request as ready for review July 25, 2026 12:52
Copilot AI review requested due to automatic review settings July 25, 2026 12:52
@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds inline Node, Python, Go, and Java sources for Copilot SDK engine drivers.

Changes:

  • Parses and validates inline driver configuration.
  • Materializes drivers and installs runtime-specific SDK dependencies.
  • Adds runtime detection, tests, schema, editor metadata, and documentation.
Show a summary per file
File Description
pkg/workflow/runtime_setup_integration_test.go Tests compiled Python driver setup.
pkg/workflow/runtime_detection.go Detects inline driver runtimes.
pkg/workflow/engine.go Parses inline driver objects.
pkg/workflow/engine_validation.go Validates inline driver constraints.
pkg/workflow/copilot_inline_driver.go Generates source files and launchers.
pkg/workflow/copilot_inline_driver_test.go Tests extraction, setup, and execution.
pkg/workflow/copilot_engine_installation.go Installs language-specific SDK dependencies.
pkg/workflow/copilot_engine_execution.go Executes workspace-generated launchers.
pkg/parser/schemas/main_workflow_schema.json Defines the new driver shape.
pkg/parser/schema_test.go Tests inline-driver schema validation.
docs/src/content/docs/reference/glossary.md Updates driver terminology.
docs/src/content/docs/reference/frontmatter.md Documents inline syntax.
docs/src/content/docs/reference/frontmatter-full.md Regenerates schema reference.
docs/src/content/docs/reference/engines.md Documents runtime materialization.
docs/public/editor/autocomplete-data.json Adds editor metadata.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 15/15 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment thread pkg/workflow/engine.go Outdated
Comment on lines +303 to +306
case "java":
spec.stepName = "Install GitHub Copilot SDK (Java)"
spec.command = fmt.Sprintf(
`cd "${GITHUB_WORKSPACE}/%[1]s" && mvn -q dependency:build-classpath -Dmdep.outputFile="%[2]s"`,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 64d1d1f. The Java inline install step now checks for mvn first and downloads a pinned Maven 3.9.9 from repo.maven.apache.org when not found — no-op on GitHub-hosted runners, bootstrap fallback on self-hosted runners.

Comment on lines +2550 to +2554
# Format 2: Inline Copilot SDK driver source. Provide exactly one runtime key.
driver:
# Inline Node.js driver source written to a generated .cjs file.
# (optional)
node: "example-value"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 64d1d1f. The frontmatter-full.md example now shows exactly one runtime key (node) with a comment noting the four supported keys, satisfying the maxProperties: 1 schema constraint.

Comment thread pkg/workflow/copilot_inline_driver.go Outdated
switch d.Runtime {
case "go":
return map[string]string{
inlineCopilotSDKDriverGoModPath: fmt.Sprintf("module %s\n\ngo %s\n", inlineCopilotSDKDriverGoModuleName, constants.DefaultGoVersion),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 64d1d1f. buildInlineCopilotSDKDriverWriteStep now reads ParsedFrontmatter.RuntimesTyped.Go.Version and passes it to additionalFiles, falling back to constants.DefaultGoVersion only when no explicit pin is set. Test TestInlineGoDriverWriteStep_UsesEffectiveGoVersion verifies this.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 87/100 — Excellent

Analyzed 7 test(s): 7 design, 0 implementation, 0 violation(s).

📊 Metrics (7 tests)
Metric Value
Analyzed 7 (Go: 7, JS: 0)
✅ Design 7 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 4 (57%)
Duplicate clusters 0
Inflation No
🚨 Violations 0
Test File Classification Issues
TestExtractEngineConfig_InlineDriverSource copilot_inline_driver_test.go:13 design_test, behavioral_contract
TestValidateEngineDriver_InlineSourceRejectsNonCopilot copilot_inline_driver_test.go:33 design_test, high_value
TestCopilotEngineInstallationWithInlineDriver copilot_inline_driver_test.go:49 design_test, high_value
TestCopilotEngineExecutionStepsWithInlineDriver copilot_inline_driver_test.go:109 design_test, high_value
TestDetectRuntimeRequirements_InlineDriver copilot_inline_driver_test.go:128 design_test, behavioral_contract
TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_EngineDriverPattern (additions) schema_test.go:359 design_test, high_value
TestRuntimeSetupWithInlineCopilotDriver runtime_setup_integration_test.go:230 design_test, high_value

Verdict

passed. 0% implementation tests (threshold: 30%). All 7 tests cover behavioral contracts with proper build tags, table-driven subtests, and no forbidden mocking libraries. The new integration test verifies end-to-end compile-to-lock-file output with step-ordering assertions.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 54.5 AIC · ⌖ 14.2 AIC · ⊞ 8.1K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 87/100. 0% implementation tests (threshold: 30%).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (595 new lines in pkg/ and other directories) but does not have a linked Architecture Decision Record (ADR).

Draft ADR committed: docs/adr/47991-inline-engine-driver-sources.md — review and complete it before merging.

This PR cannot merge until an ADR is linked in the PR body.

What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff

  2. Complete the missing sections — add context the AI could not infer, refine the decision rationale, and list real alternatives you considered

  3. Commit the finalized ADR to docs/adr/ on your branch

  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-47991: Extend engine.driver to Accept Inline Source Objects

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

Why ADRs Matter

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 47991-inline-engine-driver-sources.md for PR #47991).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · sonnet46 · 77 AIC · ⌖ 12.5 AIC · ⊞ 8.5K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Add inline engine.driver sources for Copilot SDK workflows

The overall design is solid — clean struct separation, good validation gating on copilot-only, runtime detection integration, and solid test coverage.

One blocking bug requires a fix before merge:

🔴 Java wrapper passes source file path instead of class name (blocking)

In copilot_inline_driver.go line 56, the Java wrapper script does:

exec java -cp "$CLASSPATH_CONTENT" "${GITHUB_WORKSPACE}/.../Main.java" "$@"

This is incorrect — java -cp expects a class name as the last positional argument, not a path to a .java source file. The fix is to use the inlineCopilotSDKDriverJavaMainClass constant ("Main") already defined in the file.

🟡 Non-blocking issues

  • Dead code in getInlineCopilotSDKInstallSpectypescript, rust, dotnet cases are unreachable given current validation.
  • Silent multi-key discard in applyEngineDriverField — when multiple runtime keys are present, the first is silently used; a validation error would be more user-friendly.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 38.5 AIC · ⌖ 4.8 AIC · ⊞ 5K

Comments that could not be inline-anchored

pkg/workflow/copilot_inline_driver.go:56

Bug: Java wrapper passes source file path instead of class name

The exec java -cp &quot;$CLASSPATH_CONTENT&quot; &quot;${GITHUB_WORKSPACE}/.../Main.java&quot; command is incorrect. When using -cp, the last argument to java must be the main class name (e.g., Main), not a path to a .java source file. A .java file is source code — this command fails at runtime with a class-not-found or illegal argument error.

Suggested fix:

exec java -cp &quot;$CLASSPATH_CONTENT&quot; Main &quot;$@&quot;

The `inlineCop…

pkg/workflow/copilot_engine_installation.go:250

Dead code: unreachable typescript, rust, dotnet cases

getInlineCopilotSDKInstallSpec has cases for &quot;typescript&quot;, &quot;rust&quot;, and &quot;dotnet&quot; but the validation in validateInlineEngineDriver and applyEngineDriverField only allows node, python, go, java. These branches can never be reached at runtime.

Either:

  • Remove the dead cases to keep the code consistent with validation, or
  • Add the missing runtimes to validation/schema if they are intentionally planned.

@copilo

pkg/workflow/engine.go:151

Silent discard of multiple runtime keys

When a driver map contains more than one runtime key (e.g., both node: and python:), applyEngineDriverField silently uses the first one it finds in the fixed iteration order and discards the rest. This could be confusing for workflow authors who accidentally provide multiple keys expecting an error.

Consider returning an error when more than one runtime key is present, consistent with the schema comment "Provide exactly one runtime key".

@c…

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /codebase-design and /tdd — requesting changes on three correctness issues and one dead-code hygiene issue.

📋 Key Themes & Highlights

Issues

  • Dead code (lines 287–302 of copilot_engine_installation.go): typescript, rust, dotnet cases in getInlineCopilotSDKInstallSpec are unreachable — the supported runtime set is enforced earlier and those arms silently fall back to the Node.js default.
  • Incorrect Java wrapper fallback (copilot_inline_driver.go line 56): The exec java fallback when classpath.txt is absent passes a .java source path as the main class argument, which is not valid JVM invocation syntax.
  • Go go run at execution time (copilot_inline_driver.go line 54): Recompiles on every invocation; consider compiling to a binary during install.
  • Silent multi-runtime selection (engine.go line 476): A driver map with multiple non-empty runtime keys silently picks the first one; this should be validated and rejected with a clear error.

Positive Highlights

  • ✅ Good test coverage across all four runtimes in both unit and integration tests
  • ✅ Clean separation: parsing, validation, materialisation, and runtime detection are each in their own focused function
  • ✅ Heredoc delimiter randomisation (GenerateHeredocDelimiterFromContent) prevents content collisions
  • ✅ Validation correctly gates inline drivers to the Copilot engine only

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 63 AIC · ⌖ 5.14 AIC · ⊞ 6.7K
Comment /matt to run again

spec.command = workspaceCommandPrefix + "cargo add github-copilot-sdk@" + version
case "dotnet":
spec.stepName = "Install GitHub Copilot SDK (.NET)"
spec.command = workspaceCommandPrefix + "dotnet add package GitHub.Copilot.SDK --version " + version

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] Dead code: typescript, rust, and dotnet cases in getInlineCopilotSDKInstallSpec are unreachable — applyEngineDriverField only accepts node, python, go, java, and validateInlineEngineDriver enforces the same set. These arms silently fall back to a Node.js install command instead of returning an error, which will confuse future contributors.

💡 Suggested fix

Remove the three unreachable cases, or annotate them with a TODO that names the tracking work item. Either way, add a default arm that returns an empty spec with a log line so future callers fail loudly.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 412cd47. Removed the typescript, rust, and dotnet cases from getInlineCopilotSDKInstallSpec — they were unreachable since applyEngineDriverField only populates InlineDriver for node, python, go, and java. No default arm was needed because the function already returns the Node.js spec as the default when no case matches.

Comment thread pkg/workflow/copilot_inline_driver.go Outdated
case "go":
return "#!/usr/bin/env bash\nset -euo pipefail\ncd \"${GITHUB_WORKSPACE}/" + inlineCopilotSDKDriverDir + "\"\nexec go run \"" + inlineCopilotSDKDriverGoPath[strings.LastIndex(inlineCopilotSDKDriverGoPath, "/")+1:] + "\" \"$@\"\n"
case "java":
return "#!/usr/bin/env bash\nset -euo pipefail\nif [ -f \"${GITHUB_WORKSPACE}/" + inlineCopilotSDKDriverJavaClassPath + "\" ]; then\n CLASSPATH_CONTENT=$(cat \"${GITHUB_WORKSPACE}/" + inlineCopilotSDKDriverJavaClassPath + "\")\n exec java -cp \"$CLASSPATH_CONTENT\" \"${GITHUB_WORKSPACE}/" + sourcePath + "\" \"$@\"\nfi\nexec java \"${GITHUB_WORKSPACE}/" + sourcePath + "\" \"$@\"\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] The Java wrapper script falls back to exec java "${GITHUB_WORKSPACE}/..." when classpath.txt is missing. java does not accept a source-file path as its first argument in standard mode — the fallback would fail with a cryptic JVM error. Either omit the fallback entirely (require classpath) or clarify the intent with a comment.

💡 Suggested fix

If classpath.txt is always generated by the Maven step, treat its absence as a hard failure:

#!/usr/bin/env bash
set -euo pipefail
CLASSPATH_CONTENT=$(cat "${GITHUB_WORKSPACE}/.gh-aw/copilot-sdk/classpath.txt")
exec java -cp "$CLASSPATH_CONTENT" Main "$@"

This makes the failure mode obvious rather than producing a confusing JVM usage error at runtime.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 412cd47. The Java wrapper now uses cat unconditionally to read classpath.txt, removing the if [ -f ... ] guard and the plain-java fallback. If classpath.txt is absent, cat exits with a clear "No such file or directory" error rather than proceeding to a cryptic JVM invocation. Test TestInlineJavaWrapperScript_RequiresClasspath verifies the new behavior.

Comment thread pkg/workflow/copilot_inline_driver.go Outdated
case "python":
return "#!/usr/bin/env bash\nset -euo pipefail\nexec python3 \"${GITHUB_WORKSPACE}/" + sourcePath + "\" \"$@\"\n"
case "go":
return "#!/usr/bin/env bash\nset -euo pipefail\ncd \"${GITHUB_WORKSPACE}/" + inlineCopilotSDKDriverDir + "\"\nexec go run \"" + inlineCopilotSDKDriverGoPath[strings.LastIndex(inlineCopilotSDKDriverGoPath, "/")+1:] + "\" \"$@\"\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] The Go wrapper uses go run at execution time, which recompiles the driver on every agent invocation. This adds latency and requires the Go toolchain at runtime (it must already be installed). Consider compiling to a binary during the install step instead, similar to how the Java classpath is materialized.

💡 Suggested alternative

Add a go build -o inline-driver-bin ./inline-driver.go command to the install step and point the wrapper at the binary. This avoids compile-time overhead on every execution and matches what Node/Python/Java do (they run pre-installed artifacts, not source).

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 412cd47. The Go install step now appends && go build -o inline-driver-bin ./inline-driver.go after go get, compiling the driver to a binary at install time. The wrapper script execs inline-driver-bin directly instead of using go run, eliminating per-invocation recompilation. Tests TestInlineGoInstallStep_CompilesBinary and TestInlineGoWrapperScript_ExecsBinaryNotGoRun verify this.

Comment thread pkg/workflow/copilot_inline_driver.go Outdated
appendHeredocWrite := func(path, content string, chmod bool) {
delimiter := GenerateHeredocDelimiterFromContent("INLINE_COPILOT_SDK_DRIVER", content)
step = append(step, fmt.Sprintf(" cat > \"${GITHUB_WORKSPACE}/%s\" << '%s'", path, delimiter))
for line := range strings.SplitSeq(content, "\n") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The heredoc loop uses strings.SplitSeq which preserves a trailing empty string when content ends with (very common for source files). This would emit an extra blank line after the delimiter that breaks the heredoc. There is no unit test for this boundary condition.

💡 Suggested test

Add a test case in copilot_inline_driver_test.go that verifies a source string ending in produces valid shell output with no stray blank lines after the content block:

func TestBuildInlineCopilotSDKDriverWriteStep_TrailingNewline(t *testing.T) {
    d := &InlineEngineDriver{Runtime: "python", Source: "print('hello')
"}
    step := buildInlineCopilotSDKDriverWriteStep(...)
    // assert no blank line appears between content and delimiter
}

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 412cd47. The appendHeredocWrite helper now calls strings.TrimSuffix(content, "\n") before splitting, so a source file ending with \n no longer emits an extra blank line between the last content line and the heredoc delimiter. Test TestHeredocWrite_TrailingNewlineDoesNotProduceBlankLine verifies this boundary condition.

Comment thread pkg/workflow/engine.go Outdated
for _, runtime := range []string{"node", "python", "go", "java"} {
source, ok := driverMap[runtime].(string)
if !ok || source == "" {
continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] When a driver map contains multiple runtime keys (e.g., node: and python: both set), applyEngineDriverField silently picks whichever comes first in the ordered iteration slice. A user mistake produces no error — a confusing silent behaviour. Consider rejecting driver maps with more than one non-empty key.

💡 Suggested fix

Count non-empty keys before selecting:

var matched []string
for _, runtime := range []string{"node", "python", "go", "java"} {
    if s, ok := driverMap[runtime].(string); ok && s != "" {
        matched = append(matched, runtime)
    }
}
if len(matched) > 1 {
    // return or log an error: "engine.driver: multiple runtimes specified"
}

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 412cd47. applyEngineDriverField now collects all matched runtime keys first. When more than one is present it sets InlineDriver.MultipleRuntime = true; validateInlineEngineDriver then rejects the map with "exactly one runtime key is allowed" before any engine-ID or empty-source checks run. Tests TestExtractEngineConfig_MultipleRuntimeKeys_SetsMultipleRuntimeFlag and TestValidateEngineDriver_MultipleRuntimeKeysRejected verify this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request Changes — Java driver is broken at runtime; two other medium issues

The inline driver feature is well-structured and the Node/Python/Go paths look solid, but the Java path has two bugs that will cause runtime failures, and there's a silent-misconfiguration hazard in the parser. The rest of the code (validation, runtime detection, SDK wiring, test coverage) is sound.

Blocking issues

HIGH — Java class name bug (copilot_inline_driver.go line 56): The generated wrapper passes the full filesystem path to java -cp $CLASSPATH_CONTENT, but Java expects a bare class name (Main). This will always throw ClassNotFoundException when the classpath.txt exists. Fix: use inlineCopilotSDKDriverJavaMainClass (= "Main") as the class name argument. Also note the two branches (source-launch vs. classpath-launch) are semantically inconsistent — decide on one execution model.

MEDIUM — Java install step missing mkdir -p (copilot_engine_installation.go line 1755): The cd into the SDK driver directory will fail if the directory doesn't exist. Go and Python both guard with mkdir -p; Java should too.

MEDIUM — Silent first-wins on multiple inline runtime keys (engine.go line 2151): If a user specifies more than one runtime key in the driver object, the extra keys are silently dropped. At minimum log a warning; ideally return a validation error.

Non-blocking

Dead code in getInlineCopilotSDKInstallSpec (copilot_engine_installation.go line 1736): typescript, rust, and dotnet switch cases are unreachable given the parser only accepts node/python/go/java. Remove or wire them up.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 · 94.5 AIC · ⌖ 5.17 AIC · ⊞ 5.7K
Comment /review to run again

Comments that could not be inline-anchored

pkg/workflow/copilot_inline_driver.go:56

Java wrapper passes full .java file path as the class name, causing a runtime crash: exec java -cp &quot;$CLASSPATH_CONTENT&quot; &quot;${GITHUB_WORKSPACE}/...Main.java&quot; passes a filesystem path where Java expects a bare class name (Main), so the JVM will throw ClassNotFoundException.

<details>
<summary>💡 Suggested fix</summary>

The argument after -cp &lt;classpath&gt; must be the bare class name, not a file path:

exec java -cp &quot;$CLASSPATH_CONTENT&quot; Main &quot;$@&quot;

The fallback branch (no cl…

pkg/workflow/copilot_engine_installation.go:1755

Java SDK install step will fail if the driver write step hasn't run: the Java case uses cd &quot;${GITHUB_WORKSPACE}/.gh-aw/copilot-sdk&quot; &amp;&amp; mvn ... without a mkdir -p guard, but every other runtime (Go, Python) creates the directory before cd-ing into it.

<details>
<summary>💡 Suggested fix</summary>

Add a mkdir -p guard, consistent with the Go case (line ~1743):

case &quot;java&quot;:
    spec.command = fmt.Sprintf(
        `mkdir -p &quot;${GITHUB_WORKSPACE}/%[1]s&quot; &amp;&amp; cd &quot;${GITHUB_WORKSPACE}/%…

</details>

<details><summary>pkg/workflow/engine.go:2151</summary>

**Multiple runtime keys in an inline driver object are silently ignored — no error or warning is returned**: if a user writes both `node:` and `python:` keys, the first one in the hard-coded iteration order wins and the rest are dropped without any diagnostic.

&lt;details&gt;
&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;

Count the number of non-empty runtime keys before selecting one, and return an error if more than one is present:

```go
func applyEngineDriverField(config *EngineConfig, engineObj map[strin…

</details>

<details><summary>pkg/workflow/copilot_engine_installation.go:1736</summary>

**Dead code: `typescript`, `rust`, and `dotnet` cases in `getInlineCopilotSDKInstallSpec` are unreachable**: the calling code only sets `InlineDriver.Runtime` to one of `[&quot;node&quot;,&quot;python&quot;,&quot;go&quot;,&quot;java&quot;]` (via `applyEngineDriverField`), so the three additional switch cases will never execute.

&lt;details&gt;
&lt;summary&gt;Details&lt;/summary&gt;

This is a latent maintenance trap: a future developer may think those runtimes are supported for inline drivers and add the corresponding parsing without realizing the sw…

</details>

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, fix the blocking Java inline-driver runtime issues called out in review, address the unresolved review feedback (including the multi-runtime validation concern and Java install/wrapper issues), add the required ADR link to the PR body, and rerun checks once done.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 10.8 AIC · ⌖ 8.79 AIC · ⊞ 7.1K ·
Comment /souschef to run again

…trap, Go version pin, docs example

- engine.go: preserve runtime for empty inline source so validateInlineEngineDriver
  rejects it (removes silent bypass when driver: {python: ""} is used on non-copilot
  engine or with empty content)
- copilot_engine_installation.go: Java inline driver now bootstraps Maven when not
  pre-installed; adds pinned mvnw-style download from repo.maven.apache.org (already
  in Java ecosystem allowlist) so self-hosted runners without Maven work correctly
- copilot_inline_driver.go: go.mod uses effective runtimes.go.version pin instead of
  always hardcoding constants.DefaultGoVersion
- frontmatter-full.md: inline driver example now shows exactly one runtime key (was
  showing all four, contradicting the maxProperties:1 schema rule)
- Tests: add TestExtractEngineConfig_InlineDriverEmptySourcePreserved,
  TestValidateEngineDriver_EmptyInlineSourceIsRejected,
  TestInlineJavaInstallStep_BootstrapsMaven,
  TestInlineGoDriverWriteStep_UsesEffectiveGoVersion

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, fix the blocking Java inline-driver runtime issues called out in review, address the unresolved review feedback (including the multi-runtime validation con...

Done. All four review issues are addressed in the latest commit:

  1. Empty inline source bypass (engine.go): removed the || source == "" guard in the driver map loop so empty sources are preserved and flow to validateInlineEngineDriver, which rejects them with a clear error instead of silently skipping the engine/non-Copilot checks.

  2. Java Maven bootstrap (copilot_engine_installation.go): the Java inline install step now emits a multiline run: | block that checks for mvn first (no-op on GitHub-hosted runners where Maven is pre-installed) and falls back to downloading a pinned Maven 3.9.9 from repo.maven.apache.org (already in the Java ecosystem firewall allowlist) on self-hosted runners.

  3. Go module version (copilot_inline_driver.go): buildInlineCopilotSDKDriverWriteStep now reads ParsedFrontmatter.RuntimesTyped.Go.Version and passes it through to additionalFiles; falls back to constants.DefaultGoVersion only when no explicit pin is set.

  4. Docs example (frontmatter-full.md): the driver block now shows exactly one runtime key (node), with a note that the four supported keys are node, python, go, and java, satisfying the maxProperties: 1 schema constraint.

Tests added for all four fixes.

Copilot AI requested a review from gh-aw-bot July 25, 2026 13:52
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot update instructions in .github/aw/*.md for using a custom driver / copilot-sdk

Document the new inline object form for engine.driver in the copilot-sdk
section: one runtime key (node/python/go/java), materialization under
.gh-aw/copilot-sdk/, automatic SDK installation, and constraints.
Include YAML examples for all four supported runtimes.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot update instructions in .github/aw/*.md for using a custom driver / copilot-sdk

Done in the latest commit. Updated .github/aw/syntax-agentic.md to document the inline engine.driver object form under the copilot-sdk section:

  • Explains the inline syntax (object with exactly one runtime key: node, python, go, or java) versus the existing string path/command form
  • Documents what the compiler materializes at runtime (source file + launcher wrapper under .gh-aw/copilot-sdk/, automatic SDK installation)
  • Includes YAML examples for all four supported runtimes
  • Notes the constraints (copilot engine only, exactly one runtime key, non-empty source, runtimes.<id>.version pin support)

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review feedback if any, and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 3.29 AIC · ⌖ 8.12 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI and others added 2 commits July 25, 2026 14:24
…pile, heredoc newline, multi-runtime rejection

- Remove unreachable typescript/rust/dotnet cases from getInlineCopilotSDKInstallSpec;
  these were dead code since applyEngineDriverField only accepts node/python/go/java
- Java wrapper: drop conditional fallback (exec java without classpath); cat classpath.txt
  directly so missing file produces a clear error instead of a cryptic JVM error
- Go driver: compile to binary during install (go build -o inline-driver-bin) so the
  wrapper execs the pre-built binary instead of go run on every invocation
- Heredoc trailing newline: trim suffix '\n' before SplitSeq so source files ending
  with a newline don't emit an extra blank line before the heredoc delimiter
- Multiple runtime keys: detect all matched keys before selecting; set MultipleRuntime
  flag so validateInlineEngineDriver can reject the map with a clear error
- Tests: add TestValidateEngineDriver_MultipleRuntimeKeysRejected,
  TestExtractEngineConfig_MultipleRuntimeKeys_SetsMultipleRuntimeFlag,
  TestInlineGoInstallStep_CompilesBinary, TestInlineGoWrapperScript_ExecsBinaryNotGoRun,
  TestInlineJavaWrapperScript_RequiresClasspath,
  TestHeredocWrite_TrailingNewlineDoesNotProduceBlankLine

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
…k-line check

- copilot_inline_driver.go: use strings.TrimRight(content, \"\\n\") instead of
  TrimSuffix to strip all trailing newlines, not just one
- copilot_inline_driver_test.go: fix TestHeredocWrite test to:
  - strip heredoc single-quotes from delimiter before searching for it
  - add delimiterFound flag to stop scanning after delimiter is located
  - assert heredocFound so test doesn't silently pass if step format changes

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review feedback if any, and rerun checks once the branch is up to date.

...

Done. All unresolved review threads addressed across two commits (412cd47 and the follow-up):

github-actions[bot] threads (5 new issues):

  • Dead code (typescript/rust/dotnet in getInlineCopilotSDKInstallSpec) — removed; those arms were unreachable
  • Java wrapper fallback — dropped the conditional if [ -f ... ]; cat classpath.txt now fails clearly when absent
  • Go go run — install step now runs go build -o inline-driver-bin; wrapper execs the binary directly
  • Heredoc trailing newline — changed TrimSuffixTrimRight to strip all trailing newlines before splitting
  • Multiple runtime keysapplyEngineDriverField detects all matches and sets InlineDriver.MultipleRuntime; validation rejects with a clear error

Previously-outdated copilot reviewer threads:

  • Java Maven bootstrap, Go version pin, frontmatter example — all replied to and marked as resolved

Mergeable state: PR is open, not draft, mergeable_state: unstable (CI checks reflect a prior HEAD). Local validation (make fmt, make agent-report-progress-no-test, make test-unit-all) all pass. CI must be re-triggered by a maintainer (close/reopen or push) before merge.

@pelikhan

Copy link
Copy Markdown
Collaborator

/matt

@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@pelikhan
pelikhan merged commit 3bb6a81 into main Jul 25, 2026
28 checks passed
@pelikhan
pelikhan deleted the copilot/extend-engine-driver-syntax branch July 25, 2026 14:47
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.83.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants