-
Notifications
You must be signed in to change notification settings - Fork 739
feat(harness): Initial Claude Code Support #2602
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+5,539
−259
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
08c16ed
claude initial commit
supreme-gg-gg 27daee7
mcp, skills, plugins, fixes to claude
supreme-gg-gg 0996619
rebase and go mod
supreme-gg-gg 0a0c552
add claude code docs
supreme-gg-gg 8b5b10c
fix lint and test
supreme-gg-gg c83bf4c
fix claude e2e mcp tests
supreme-gg-gg 06249f5
fix codex review comments
supreme-gg-gg c835032
e2e: add fork and resume
supreme-gg-gg f4eba20
review comments
supreme-gg-gg 991566e
add timeout to claude
supreme-gg-gg f402b97
review comments
supreme-gg-gg 9c7d701
test rename
supreme-gg-gg b739599
refactor agentplugin for better modularity
supreme-gg-gg 9a9265e
fix artifact streaming chat
supreme-gg-gg 05abbf2
update claude tests
supreme-gg-gg 2c98991
fix claude streaming dedup
supreme-gg-gg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -120,7 +120,7 @@ jobs: | |
| --push | ||
| run: | | ||
| echo "Cache key: ${{ needs.setup.outputs.cache-key }}" | ||
| make build-controller build-golang-adk | ||
| make build-controller build-golang-adk build-claude-harness | ||
| make helm-install-provider | ||
| kubectl rollout status deployment/kagent-controller -n kagent --timeout=120s | ||
| kubectl wait --for=condition=Ready pod -l app.kubernetes.io/component=controller -n kagent --timeout=120s | ||
|
|
@@ -132,6 +132,9 @@ jobs: | |
| RUNTIME_DIGEST=$(docker buildx imagetools inspect "localhost:5001/kagent-dev/kagent/golang-adk:${VERSION}" | awk '$1 == "Digest:" { print $2; exit }') | ||
| test -n "$RUNTIME_DIGEST" | ||
| export KAGENT_E2E_RUNTIME_IMAGE="localhost:5001/kagent-dev/kagent/golang-adk@${RUNTIME_DIGEST}" | ||
| CLAUDE_DIGEST=$(docker buildx imagetools inspect "localhost:5001/kagent-dev/kagent/claude-harness:${VERSION}" | awk '$1 == "Digest:" { print $2; exit }') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not blocking, I don't want to end up in a situation like last release where the controller build was completely blocked on these dependencies |
||
| test -n "$CLAUDE_DIGEST" | ||
| export KAGENT_E2E_CLAUDE_IMAGE="localhost:5001/kagent-dev/kagent/claude-harness@${CLAUDE_DIGEST}" | ||
| envsubst < core/test/e2e/manifests/lifecycle.yaml.tmpl | kubectl apply -f - | ||
| for _ in $(seq 1 60); do | ||
| READY=$(kubectl get agenttemplate smoke -n kagent -o jsonpath='{.status.harnesses[?(@.harness=="kagent")].conditions[?(@.type=="Ready")].status}') | ||
|
|
@@ -413,6 +416,7 @@ jobs: | |
| - kagent-adk | ||
| - cli | ||
| - golang-adk | ||
| - claude-harness | ||
| runs-on: ubuntu-latest | ||
| services: | ||
| registry: | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| package config | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "path/filepath" | ||
|
|
||
| "github.com/kagent-dev/kagent/go/api/adk" | ||
| "github.com/kagent-dev/kagent/go/core/v2/agentplugins" | ||
| ) | ||
|
|
||
| // AgentPluginPaths contains the ADK runtime destinations for Agent Plugin | ||
| // packages, selected skills, and mutable MCP server data. | ||
| type AgentPluginPaths struct { | ||
| Packages string | ||
| Skills string | ||
| Data string | ||
| } | ||
|
|
||
| // MaterializeAgentPlugins materializes plugins independently for each agent | ||
| // and adds their skills and MCP servers to the ADK runtime configuration. | ||
| func MaterializeAgentPlugins(ctx context.Context, agentConfig *adk.AgentConfig, paths AgentPluginPaths) error { | ||
| if agentConfig.AgentPlugins != nil { | ||
| materialization, err := agentplugins.Materialize(ctx, *agentConfig.AgentPlugins, agentplugins.Paths{ | ||
| Packages: paths.Packages, | ||
| Skills: paths.Skills, | ||
| }) | ||
| if err != nil { | ||
| return fmt.Errorf("materialize agent plugins: %w", err) | ||
| } | ||
| mcpConfig, err := agentplugins.LoadMCP(ctx, materialization, paths.Data) | ||
| if err != nil { | ||
| return fmt.Errorf("load agent plugin MCP configuration: %w", err) | ||
| } | ||
| addMCPConfig(agentConfig, mcpConfig) | ||
| agentConfig.SkillsDirectory = materialization.SkillsDirectory | ||
| } | ||
| for i, child := range agentConfig.SubAgents { | ||
| childRoot := filepath.Join("subagents", fmt.Sprintf("%d", i)) | ||
| if err := MaterializeAgentPlugins(ctx, child, AgentPluginPaths{ | ||
| Packages: filepath.Join(paths.Packages, childRoot), | ||
| Skills: filepath.Join(paths.Skills, childRoot), | ||
| Data: filepath.Join(paths.Data, childRoot), | ||
| }); err != nil { | ||
| return fmt.Errorf("materialize sub-agent %q: %w", child.Name, err) | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func addMCPConfig(agentConfig *adk.AgentConfig, mcpConfig agentplugins.MCPConfig) { | ||
| for _, server := range mcpConfig.StreamableHTTP { | ||
| agentConfig.HttpTools = append(agentConfig.HttpTools, adk.HttpMcpServerConfig{ | ||
| Params: adk.StreamableHTTPConnectionParams{Url: server.URL, Headers: server.Headers}, | ||
| }) | ||
| } | ||
| for _, server := range mcpConfig.SSE { | ||
| agentConfig.SseTools = append(agentConfig.SseTools, adk.SseMcpServerConfig{ | ||
| Params: adk.SseConnectionParams{Url: server.URL, Headers: server.Headers}, | ||
| }) | ||
| } | ||
| for _, server := range mcpConfig.Stdio { | ||
| agentConfig.StdioTools = append(agentConfig.StdioTools, adk.StdioMcpServerConfig{ | ||
| Command: server.Command, | ||
| Args: server.Args, | ||
| Env: server.Env, | ||
| Dir: server.Dir, | ||
| }) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| package config | ||
|
|
||
| import ( | ||
| "context" | ||
| "os" | ||
| "path/filepath" | ||
| "strings" | ||
| "testing" | ||
|
|
||
| "github.com/kagent-dev/kagent/go/api/adk" | ||
| "github.com/kagent-dev/kagent/go/api/agentplugin" | ||
| "github.com/kagent-dev/kagent/go/core/v2/agentplugins" | ||
| ) | ||
|
|
||
| func TestMaterializeAgentPluginsIsolatesSubagentSkills(t *testing.T) { | ||
| root := t.TempDir() | ||
| paths := AgentPluginPaths{ | ||
| Packages: filepath.Join(root, "packages"), | ||
| Skills: filepath.Join(root, "skills"), | ||
| Data: filepath.Join(root, "data"), | ||
| } | ||
| source := agentplugin.Source{Git: &agentplugin.GitSource{URL: "unused", Commit: strings.Repeat("a", 40)}} | ||
| agentConfig := &adk.AgentConfig{ | ||
| AgentPlugins: &agentplugin.Resources{Skills: []agentplugin.Skill{{Name: "root", Source: source}}}, | ||
| SubAgents: []*adk.AgentConfig{{Name: "child", AgentPlugins: &agentplugin.Resources{Skills: []agentplugin.Skill{{Name: "child", Source: source}}}}}, | ||
| } | ||
| for _, path := range []string{ | ||
| filepath.Join(paths.Packages, "standalone-0"), | ||
| filepath.Join(paths.Packages, "subagents", "0", "standalone-0"), | ||
| } { | ||
| if err := os.MkdirAll(path, 0o755); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if err := os.WriteFile(filepath.Join(path, "SKILL.md"), []byte("# Skill"), 0o644); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| } | ||
| if err := MaterializeAgentPlugins(context.Background(), agentConfig, paths); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if agentConfig.SkillsDirectory == agentConfig.SubAgents[0].SkillsDirectory { | ||
| t.Fatalf("root and child share skills directory %q", agentConfig.SkillsDirectory) | ||
| } | ||
| for _, path := range []string{ | ||
| filepath.Join(agentConfig.SkillsDirectory, "root", "SKILL.md"), | ||
| filepath.Join(agentConfig.SubAgents[0].SkillsDirectory, "child", "SKILL.md"), | ||
| } { | ||
| if _, err := os.Stat(path); err != nil { | ||
| t.Fatalf("materialized skill %q: %v", path, err) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func TestAddMCPConfigConvertsRuntimeNeutralServers(t *testing.T) { | ||
| agentConfig := &adk.AgentConfig{} | ||
| addMCPConfig(agentConfig, agentplugins.MCPConfig{ | ||
| StreamableHTTP: []agentplugins.RemoteMCPServer{{URL: "https://http.example.com", Headers: map[string]string{"X-Test": "http"}}}, | ||
| SSE: []agentplugins.RemoteMCPServer{{URL: "https://sse.example.com", Headers: map[string]string{"X-Test": "sse"}}}, | ||
| Stdio: []agentplugins.StdioMCPServer{{Command: "server", Args: []string{"--serve"}, Env: map[string]string{"KEY": "value"}, Dir: "/plugin"}}, | ||
| }) | ||
|
|
||
| if len(agentConfig.HttpTools) != 1 || agentConfig.HttpTools[0].Params.Url != "https://http.example.com" { | ||
| t.Fatalf("HTTP tools = %#v", agentConfig.HttpTools) | ||
| } | ||
| if len(agentConfig.SseTools) != 1 || agentConfig.SseTools[0].Params.Url != "https://sse.example.com" { | ||
| t.Fatalf("SSE tools = %#v", agentConfig.SseTools) | ||
| } | ||
| if len(agentConfig.StdioTools) != 1 || agentConfig.StdioTools[0].Command != "server" { | ||
| t.Fatalf("stdio tools = %#v", agentConfig.StdioTools) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the future we should add
-jhere so we can parallelize these builds across the runner CPUs