skillsFromParts reconstructs skill metadata from persisted skill parts. This is analogous to instructionFromContextFiles so the skill index can be re-injected after compaction without re-dialing the workspace agent.
( messages []database.ChatMessage, )
| 207 | // so the skill index can be re-injected after compaction without |
| 208 | // re-dialing the workspace agent. |
| 209 | func skillsFromParts( |
| 210 | messages []database.ChatMessage, |
| 211 | ) []chattool.SkillMeta { |
| 212 | filterAgentID, filterByAgent := latestContextAgentID(messages) |
| 213 | var skills []chattool.SkillMeta |
| 214 | for _, msg := range messages { |
| 215 | if !msg.Content.Valid || |
| 216 | !bytes.Contains(msg.Content.RawMessage, []byte(`"skill"`)) { |
| 217 | continue |
| 218 | } |
| 219 | var parts []codersdk.ChatMessagePart |
| 220 | if err := json.Unmarshal(msg.Content.RawMessage, &parts); err != nil { |
| 221 | continue |
| 222 | } |
| 223 | for _, part := range parts { |
| 224 | if part.Type != codersdk.ChatMessagePartTypeSkill { |
| 225 | continue |
| 226 | } |
| 227 | if filterByAgent && part.ContextFileAgentID.Valid && |
| 228 | part.ContextFileAgentID.UUID != filterAgentID { |
| 229 | continue |
| 230 | } |
| 231 | skills = append(skills, chattool.SkillMeta{ |
| 232 | Name: part.SkillName, |
| 233 | Description: part.SkillDescription, |
| 234 | Dir: part.SkillDir, |
| 235 | MetaFile: part.ContextFileSkillMetaFile, |
| 236 | }) |
| 237 | } |
| 238 | } |
| 239 | return skills |
| 240 | } |
| 241 | |
| 242 | // filterSkillParts returns stripped copies of skill-type parts from |
| 243 | // the given slice. Internal fields are removed so the result is safe |