import {
agent_session_active_skills,
agent_session_messages,
agent_session_record_skill_event,
agent_session_set_active_skills,
} from "std/agent/state"
fn __skills_registry(opts) {
let registry = opts?.skill_registry ?? opts?.skills
if type_of(registry) == "list" {
return {_type: "skill_registry", skills: registry}
}
return registry
}
fn __skills_entries(registry) {
if registry == nil {
return []
}
return registry?.skills ?? []
}
fn __skill_id(entry) {
return entry?.id ?? entry?.name ?? ""
}
fn __skill_find(registry, id) {
for entry in __skills_entries(registry) {
if __skill_id(entry) == id {
return entry
}
}
return nil
}
fn __skill_ids(entries) {
var ids = []
for entry in entries {
let id = __skill_id(entry)
if id != "" {
ids = ids.push(id)
}
}
return ids
}
fn __tool_registry_has(registry, name) {
if type_of(registry) != "dict" {
return false
}
for tool_entry in registry?.tools ?? [] {
if __tool_name(tool_entry) == name {
return true
}
}
return false
}
fn __render_loaded_skill(entry, request) {
let rendered = try {
skill_render(entry, request?.arguments ?? request?.args ?? [])
}
if !is_err(rendered) {
let body = trim(unwrap(rendered))
if body != "" {
return body
}
}
var out = "### " + __skill_id(entry) + "\n"
let description = trim(entry?.description ?? "")
if description != "" {
out = out + description + "\n"
}
let when_to_use = trim(entry?.when_to_use ?? "")
if when_to_use != "" {
out = out + "When to use: " + when_to_use + "\n"
}
let allowed = entry?.allowed_tools ?? []
if len(allowed) > 0 {
out = out + "Scoped tools: " + join(allowed, ", ") + "\n"
}
let prompt = trim(entry?.prompt ?? "")
if prompt != "" {
out = out + "\n" + prompt + "\n"
}
return trim(out)
}
fn __load_skill_for_session(session, opts, args) {
let request = if type_of(args) == "dict" {
args
} else {
{name: args}
}
let registry = __skills_registry(opts)
let id = request?.name ?? ""
let entry = __skill_find(registry, id)
let require_signature = request?.require_signature ?? false || entry?.require_signature ?? false
if entry == nil || require_signature {
return load_skill(request + {session_id: session.session_id})
}
if __skill_model_invocation_disabled(entry) {
throw "skill_model_invocation_disabled: skill '" + id + "' cannot be loaded by a model"
}
let loaded = try {
load_skill(request + {session_id: session.session_id})
}
let body = if is_err(loaded) {
__render_loaded_skill(entry, request)
} else {
unwrap(loaded)
}
if entry != nil {
let prev = __active_from_ids(registry, agent_session_active_skills(session.session_id) ?? [])
var next = prev
if !contains(__skill_ids(prev), id) {
next = next.push(entry + {id: id, score: 1.0, trigger: "load_skill"})
__record_activations(session, prev, next, 0)
agent_session_set_active_skills(session.session_id, next)
}
}
return body
}
fn __with_load_skill_tool(session, opts) {
let existing = opts?.tools
let registry = if type_of(existing) == "dict" {
existing
} else {
tool_registry()
}
if __tool_registry_has(registry, "load_skill") {
return opts + {tools: registry}
}
let next_registry = tool_define(
registry,
"load_skill",
"Load the full instructions for a skill from the active skill catalog",
{
parameters: {
name: {type: "string", description: "Skill id from the catalog"},
require_signature: {
type: "boolean",
description: "Reject the skill unless provenance shows a trusted signature",
required: false,
},
},
handler: { args -> __load_skill_for_session(session, opts, args) },
},
)
return opts + {tools: next_registry}
}
fn __skills_same_ids(prev, next) {
let prev_ids = __skill_ids(prev)
let next_ids = __skill_ids(next)
if len(prev_ids) != len(next_ids) {
return false
}
for (index, id) in iter(next_ids).enumerate() {
if prev_ids[index] != id {
return false
}
}
return true
}
fn __active_from_ids(registry, ids) {
var active = []
for item in ids {
let id = item?.id ?? item?.name ?? item
let entry = __skill_find(registry, id)
if entry != nil {
active = active.push(entry + {id: id})
}
}
return active
}
fn __latest_user_text(session) {
var latest = session?.task ?? ""
for message in agent_session_messages(session.session_id) {
if message?.role == "user" {
latest = message?.content ?? latest
}
}
return latest
}
fn __match_config(opts) {
return opts?.skill_match ?? {}
}
fn __match_strategy(opts) {
return __match_config(opts)?.strategy ?? "catalog"
}
fn __match_strategy_manual(opts) {
let strategy = __match_strategy(opts)
return strategy == "manual" || strategy == "none"
}
fn __match_top_n(opts) {
let value = __match_config(opts)?.top_n
if type_of(value) == "int" && value > 0 {
return value
}
return 1
}
fn __match_sticky(opts) {
let value = __match_config(opts)?.sticky
if type_of(value) == "bool" {
return value
}
return true
}
fn __skill_catalog_limit(opts) {
let value = __match_config(opts)?.catalog_limit ?? opts?.skill_catalog_limit ?? 12
if type_of(value) == "int" && value > 0 {
return value
}
return 12
}
fn __skill_catalog_budget(opts) {
let value = __match_config(opts)?.catalog_budget ?? opts?.skill_catalog_budget ?? 2000
if type_of(value) == "int" && value > 0 {
return value
}
return 2000
}
fn __skill_catalog_always(opts) {
let value = __match_config(opts)?.catalog_always ?? opts?.skill_catalog_always
if type_of(value) == "bool" {
return value
}
return false
}
fn __skill_catalog_prompt(registry, opts, active) {
if __match_strategy(opts) != "catalog" {
return ""
}
if len(active ?? []) > 0 && !__skill_catalog_always(opts) {
return ""
}
let entries = skills_catalog_entries({_type: "skill_registry", skills: __matchable_skill_entries(registry)})
if len(entries) == 0 {
return ""
}
return render_always_on_catalog(entries.take(__skill_catalog_limit(opts)), __skill_catalog_budget(opts))
}
fn __skill_model_invocation_disabled(entry) {
return entry["disable-model-invocation"] ?? false || entry?.disable_model_invocation ?? false
}
fn __matchable_skill_entries(registry) {
var entries = []
for entry in __skills_entries(registry) {
if !__skill_model_invocation_disabled(entry) {
entries = entries.push(entry)
}
}
return entries
}
fn __skill_score_stop_words() {
return [
"able",
"about",
"add",
"after",
"all",
"and",
"any",
"are",
"ask",
"can",
"clean",
"code",
"create",
"does",
"file",
"for",
"from",
"has",
"have",
"how",
"into",
"its",
"make",
"more",
"need",
"not",
"one",
"only",
"other",
"read",
"run",
"space",
"task",
"test",
"that",
"the",
"then",
"this",
"tool",
"use",
"user",
"when",
"with",
"work",
"write",
"you",
"your",
]
}
fn __skill_score_tokens(text) {
let normalized = regex_replace("[^A-Za-z0-9]+", " ", lowercase(to_string(text ?? "")))
let stop_words = __skill_score_stop_words()
var out = []
for raw in split(trim(normalized), " ") {
let token = trim(raw)
if len(token) > 2 && !contains(stop_words, token) && !contains(out, token) {
out = out.push(token)
}
}
return out
}
fn __skill_score_term_hits(query_tokens, text) {
let haystack_tokens = __skill_score_tokens(text)
var hits = 0
for token in query_tokens {
if contains(haystack_tokens, token) {
hits = hits + 1
}
}
return hits
}
fn __skill_score_id_match(query_tokens, id) {
let id_tokens = __skill_score_tokens(id)
if len(id_tokens) == 0 {
return false
}
for token in id_tokens {
if !contains(query_tokens, token) {
return false
}
}
return true
}
fn __skill_score_glob_match(pattern, path) {
let glob = to_string(pattern ?? "")
let value = to_string(path ?? "")
if glob == "" || value == "" {
return false
}
if glob == value {
return true
}
if !contains(glob, "*") {
return false
}
let parts = split(glob, "*")
var cursor = 0
for (index, part) in iter(parts).enumerate() {
if part == "" {
continue
}
let rest = substring(value, cursor)
let offset = rest.index_of(part)
if offset < 0 {
return false
}
if index == 0 && !starts_with(glob, "*") && offset != 0 {
return false
}
cursor = cursor + offset + len(part)
}
let last = parts[len(parts) - 1]
return last == "" || ends_with(value, last)
}
fn __skill_score_path_hits(patterns, working_files) {
var hits = 0
for pattern in patterns ?? [] {
for file in working_files ?? [] {
if __skill_score_glob_match(pattern, file) {
hits = hits + 1
break
}
}
}
return hits
}
fn __skill_score_metadata(context, registry) {
let query_tokens = __skill_score_tokens(context?.task ?? "")
let working_files = context?.working_files ?? []
var scored = []
for entry in __matchable_skill_entries(registry) {
let id = __skill_id(entry)
if id == "" {
continue
}
let keyword_hits = __skill_score_term_hits(query_tokens, entry?.description ?? "")
+ __skill_score_term_hits(query_tokens, entry?.when_to_use ?? "")
let id_match = __skill_score_id_match(query_tokens, id)
let path_hits = __skill_score_path_hits(entry?.paths ?? [], working_files)
var score = 0.0
var triggers = []
if keyword_hits > 0 {
score = score + keyword_hits / (keyword_hits + 1.5)
triggers = triggers.push(to_string(keyword_hits) + " keyword hit(s)")
}
if id_match {
score = score + 2.0
triggers = triggers.push("task mentions '" + id + "'")
}
if path_hits > 0 {
score = score + 1.5 * path_hits
triggers = triggers.push(to_string(path_hits) + " path glob(s) matched")
}
if score > 0.0 {
scored = scored
.push(
{id: id, name: id, score: score, trigger: join(triggers, "; "), reason: join(triggers, "; ")},
)
}
}
return scored.sort_by({ candidate -> 0 - candidate.score })
}
fn __host_skill_score_candidates(context, registry, opts) {
let matchable = {_type: "skill_registry", skills: __matchable_skill_entries(registry)}
let outcome = try {
__host_skill_score(context, matchable, __match_config(opts))
}
if is_err(outcome) {
return __skill_score_metadata(context, registry)
}
return unwrap(outcome)?.scored ?? []
}
fn __score_candidates(session, registry, opts, iteration) {
let context = {task: __latest_user_text(session), working_files: opts?.working_files ?? [], iteration: iteration}
if __match_strategy(opts) == "metadata" {
return __skill_score_metadata(context, registry)
}
return __host_skill_score_candidates(context, registry, opts)
}
fn __top_active_from_scores(registry, scored, opts) {
var active = []
let top_n = __match_top_n(opts)
let strategy = __match_strategy(opts)
for candidate in scored {
if len(active) >= top_n {
break
}
let score = candidate?.score ?? 0.0
if score <= 0.0 && strategy == "metadata" {
continue
}
let id = candidate?.id ?? candidate?.name ?? ""
let entry = __skill_find(registry, id)
if entry != nil {
active = active.push(entry + {id: id, score: score, trigger: candidate?.trigger ?? candidate?.reason ?? ""})
}
}
return active
}
fn __record_matched(session, opts, iteration, scored) {
agent_session_record_skill_event(
session.session_id,
"skill_matched",
{
strategy: __match_strategy(opts),
iteration: iteration,
reassess: iteration > 0,
candidates: scored,
working_files: opts?.working_files ?? [],
},
)
}
fn __record_deactivations(session, prev, next, iteration) {
let next_ids = __skill_ids(next)
for entry in prev {
let id = __skill_id(entry)
if id != "" && !contains(next_ids, id) {
agent_session_record_skill_event(
session.session_id,
"skill_deactivated",
{name: id, id: id, iteration: iteration},
)
}
}
}
fn __record_activations(session, prev, next, iteration) {
let prev_ids = __skill_ids(prev)
for entry in next {
let id = __skill_id(entry)
if id == "" || contains(prev_ids, id) {
continue
}
agent_session_record_skill_event(
session.session_id,
"skill_activated",
{
name: id,
id: id,
description: entry?.description ?? "",
iteration: iteration,
score: entry?.score ?? 0.0,
trigger: entry?.trigger ?? "",
allowed_tools: entry?.allowed_tools ?? [],
},
)
if len(entry?.allowed_tools ?? []) > 0 {
agent_session_record_skill_event(
session.session_id,
"skill_scope_tools",
{name: id, id: id, allowed_tools: entry.allowed_tools},
)
}
}
}
fn __allowed_union(active) {
var allowed = []
for active_entry in active {
for allowed_entry in active_entry?.allowed_tools ?? [] {
if !contains(allowed, allowed_entry) {
allowed = allowed.push(allowed_entry)
}
}
}
return allowed
}
fn __tool_name(tool_entry) {
return tool_entry?.name ?? tool_entry?.function?.name ?? ""
}
fn __tool_namespace(tool_entry) {
return tool_entry?.namespace ?? tool_entry?.function?.namespace ?? ""
}
fn __allowed_matches_tool(entry, tool_entry) {
if entry == "*" {
return true
}
let name = __tool_name(tool_entry)
if entry == name {
return true
}
if starts_with(entry, "namespace:") {
return substring(entry, len("namespace:")) == __tool_namespace(tool_entry)
}
return false
}
fn __skill_scoped_tools(opts, active) {
let allowed = __allowed_union(active)
if len(allowed) == 0 || contains(allowed, "*") {
return opts?.tools
}
let registry = opts?.tools
if type_of(registry) != "dict" {
return registry
}
var kept = []
for tool_entry in registry?.tools ?? [] {
if __tool_name(tool_entry) == "load_skill" {
kept = kept.push(tool_entry)
continue
}
var keep = false
for entry in allowed {
if __allowed_matches_tool(entry, tool_entry) {
keep = true
break
}
}
if keep {
kept = kept.push(tool_entry)
}
}
return registry + {tools: kept}
}
fn __opts_with_active_skills(opts, registry, active) {
let scoped_tools = __skill_scoped_tools(opts, active)
var next = opts + {active_skills: active}
if scoped_tools != nil {
next = next + {tools: scoped_tools}
}
let catalog_prompt = __skill_catalog_prompt(registry, opts, active)
if catalog_prompt != "" {
next = next + {skill_catalog_prompt: catalog_prompt}
}
return next
}
/** agent_skills_match. */
pub fn agent_skills_match(session, opts, iteration) {
let registry = __skills_registry(opts)
if registry == nil || len(__skills_entries(registry)) == 0 {
return opts
}
let tool_opts = __with_load_skill_tool(session, opts)
let prev = __active_from_ids(registry, agent_session_active_skills(session.session_id) ?? [])
if __match_strategy_manual(opts) {
return __opts_with_active_skills(tool_opts, registry, prev)
}
if __match_strategy(opts) == "catalog" {
return __opts_with_active_skills(tool_opts, registry, prev)
}
if __match_sticky(opts) && len(prev) > 0 {
return __opts_with_active_skills(tool_opts, registry, prev)
}
let scored = __score_candidates(session, registry, tool_opts, iteration)
__record_matched(session, tool_opts, iteration, scored)
let active = __top_active_from_scores(registry, scored, tool_opts)
if !__skills_same_ids(prev, active) {
__record_deactivations(session, prev, active, iteration)
__record_activations(session, prev, active, iteration)
agent_session_set_active_skills(session.session_id, active)
}
return __opts_with_active_skills(tool_opts, registry, active)
}