Revert loaded skill history persistence
Some checks are pending
Build And Publish Docker Images / plan (push) Waiting to run
Build And Publish Docker Images / build (push) Blocked by required conditions

Reverts db01d7c1c8 and 3c83b2eca2.

Restores the prior loaded-skills prompt-extras behavior and removes the compaction reattachment metadata path.
This commit is contained in:
Alessandro 2026-06-18 16:45:56 +02:00
parent 8fda0ee69c
commit bf2741990a
13 changed files with 32 additions and 389 deletions

View file

@ -2,19 +2,17 @@
## Purpose
- Own prompt extras and history-output adjustments appended after primary message-loop prompt construction.
- Own prompt extras appended after primary message-loop prompt construction.
## Ownership
- Ordered Python files own current datetime, skill recall/load context, loaded-skill reattachment, agent info, parallel job status, and workdir extras injection.
- Ordered Python files own current datetime, skill recall/load context, agent info, parallel job status, and workdir extras injection.
## Local Contracts
- Keep injected content bounded and clearly attributed.
- Preserve ordering where later prompt extras depend on earlier recall or load results.
- Do not expose secrets or private files from workdir extras.
- Explicitly loaded skill instructions belong in normal tool-result history; this hook may recall candidate skills, but must not reinject loaded skill bodies through prompt extras every turn.
- If compression hides an explicitly loaded skill body, this hook may reattach the missing visible revision as a bounded normal tool-result history message.
## Work Guidance

View file

@ -1,95 +1,38 @@
from helpers.extension import Extension
from helpers import skills, tokens
from helpers import skills
from tools.skills_tool import DATA_NAME_LOADED_SKILLS
from agent import LoopData
SKILL_REATTACHMENT_TOKEN_BUDGET = 12_000
SKILL_REATTACHMENT_HEADER = (
"Reattached loaded skill instructions after history compaction."
)
class IncludeLoadedSkills(Extension):
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
if not self.agent:
return
loop_data.extras_persistent.pop("loaded_skills", None)
extras = loop_data.extras_persistent
# Get loaded skills names
skill_names = self.agent.data.get(DATA_NAME_LOADED_SKILLS)
if not skill_names:
return
# `skills_tool load` now appends full skill instructions as a normal
# tool-result history message. Keep this legacy ledger pruned, but do
# not reinject loaded skills through prompt extras every turn.
# load skill text here
content = ""
visible_skill_names = []
loaded_skills = []
for skill_name in skill_names:
skill = skills.find_skill(skill_name, agent=self.agent)
if not skill:
if not skills.find_skill(skill_name, agent=self.agent):
continue
visible_skill_names.append(skill.name)
loaded_skills.append(skill)
visible_skill_names.append(skill_name)
skill_data = skills.load_skill_for_agent(skill_name=skill_name, agent=self.agent)
content += "\n\n" + skill_data
self.agent.data[DATA_NAME_LOADED_SKILLS] = visible_skill_names
self._reattach_missing_skill_bodies(loop_data, loaded_skills)
def _reattach_missing_skill_bodies(self, loop_data: LoopData, loaded_skills):
if not self.agent or not loaded_skills:
content = content.strip()
if not content:
return
visible_revisions = _visible_skill_revisions(loop_data.history_output)
selected = []
used_tokens = 0
for skill in reversed(loaded_skills):
skill_data = skills.load_skill_for_agent(
skill_name=skill.name,
agent=self.agent,
)
revision = skills.skill_revision(skill_data)
if (skill.name, revision) in visible_revisions:
continue
message = f"{SKILL_REATTACHMENT_HEADER}\n\n{skill_data}"
message_tokens = tokens.approximate_tokens(message)
if used_tokens + message_tokens > SKILL_REATTACHMENT_TOKEN_BUDGET:
continue
selected.append((skill, revision, message))
used_tokens += message_tokens
for skill, revision, message in reversed(selected):
history_message = self.agent.hist_add_tool_result(
"skills_tool",
message,
skill_instructions={
"name": skill.name,
"path": str(skill.path),
"revision": revision,
"source": "skills_tool:reattach",
"content_included": True,
},
)
loop_data.history_output.extend(history_message.output())
def _visible_skill_revisions(history_output) -> set[tuple[str, str]]:
visible = set()
for message in history_output or []:
if not isinstance(message, dict):
continue
content = message.get("content")
if not isinstance(content, dict):
continue
meta = content.get("skill_instructions")
if not isinstance(meta, dict):
continue
if not meta.get("content_included"):
continue
name = str(meta.get("name") or "").strip()
revision = str(meta.get("revision") or "").strip()
if name and revision:
visible.add((name, revision))
return visible
# Inject into extras
extras["loaded_skills"] = self.agent.read_prompt(
"agent.system.skills.loaded.md",
skills=content,
)