78 lines
2.7 KiB
Go
78 lines
2.7 KiB
Go
package lifecycle
|
|
|
|
import (
|
|
"context"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// MetadataKeyInstructionsDir carries the per-launch path where the
|
|
// SkillDeployer wrote the agent's instruction files. Office's prompt
|
|
// builder reads from this path; kanban launches don't consume it.
|
|
const MetadataKeyInstructionsDir = "kandev_instructions_dir"
|
|
|
|
// runSkillDeploy resolves the agent profile (now including the office
|
|
// enrichment fields from ADR 0005 Wave A), short-circuits when there's
|
|
// nothing to deploy, and otherwise hands off to the configured
|
|
// SkillDeployer. Any metadata patches the deployer returns are merged
|
|
// onto the prepared LaunchRequest so executor backends see them
|
|
// (e.g. Docker bind-mount, Sprites manifest upload). Errors are logged
|
|
// and swallowed: an in-flight launch must not be aborted because skill
|
|
// materialisation hiccupped.
|
|
func (m *Manager) runSkillDeploy(ctx context.Context, original, prepared *LaunchRequest) {
|
|
if m.skillDeployer == nil || m.agentProfileReader == nil {
|
|
return
|
|
}
|
|
if original.AgentProfileID == "" {
|
|
return
|
|
}
|
|
profile, err := m.agentProfileReader.GetAgentProfile(ctx, original.AgentProfileID)
|
|
if err != nil || profile == nil {
|
|
m.logger.Debug("skill deploy skipped: profile lookup failed",
|
|
zap.String("profile_id", original.AgentProfileID),
|
|
zap.Error(err))
|
|
return
|
|
}
|
|
if len(profile.SkillIDs) == 0 && len(profile.DesiredSkills) == 0 {
|
|
// Fast path: shallow / kanban-flavour profiles with no enrichment to
|
|
// deploy. Most launches today land here.
|
|
return
|
|
}
|
|
req := SkillDeployRequest{
|
|
Profile: profile,
|
|
WorkspacePath: prepared.WorkspacePath,
|
|
ExecutorType: prepared.ExecutorType,
|
|
WorkspaceID: profile.WorkspaceID,
|
|
SessionID: original.SessionID,
|
|
}
|
|
result, err := m.skillDeployer.DeploySkills(ctx, req)
|
|
if err != nil {
|
|
m.logger.Warn("skill deploy failed; launch continues",
|
|
zap.String("profile_id", profile.ID),
|
|
zap.String("workspace_path", prepared.WorkspacePath),
|
|
zap.Error(err))
|
|
return
|
|
}
|
|
mergeSkillMetadata(prepared, result)
|
|
}
|
|
|
|
// mergeSkillMetadata applies the deployer's output to the prepared
|
|
// launch request: every metadata patch is written through, and the
|
|
// instructions directory is stamped under MetadataKeyInstructionsDir
|
|
// so downstream consumers (office prompt builder, run detail UI) can
|
|
// recover the path.
|
|
func mergeSkillMetadata(prepared *LaunchRequest, result SkillDeployResult) {
|
|
if len(result.Metadata) == 0 && result.InstructionsDir == "" {
|
|
return
|
|
}
|
|
if prepared.Metadata == nil {
|
|
prepared.Metadata = make(map[string]interface{})
|
|
}
|
|
for k, v := range result.Metadata {
|
|
prepared.Metadata[k] = v
|
|
}
|
|
if result.InstructionsDir != "" {
|
|
prepared.Metadata[MetadataKeyInstructionsDir] = result.InstructionsDir
|
|
}
|
|
}
|