mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
import type { PathNormalizer } from "#src/path-normalizer";
|
|
import { buildSkillPathAskPayload } from "#src/presentation/skill-ask-payload";
|
|
import type { SkillPromptEntry } from "#src/skill-prompt-sanitizer";
|
|
import { findSkillPathMatch } from "#src/skill-prompt-sanitizer";
|
|
import { toRecord } from "#src/value-guards";
|
|
import type { GateDescriptor } from "./descriptor";
|
|
import { accessFactsFromValue } from "./helpers";
|
|
import type { ToolCallContext } from "./types";
|
|
|
|
/**
|
|
* Build a pure descriptor for the skill-read permission gate.
|
|
*
|
|
* Returns `null` when the gate does not apply (tool is not `read`, no active
|
|
* skill entries, or the read path does not match any skill).
|
|
* Returns a GateDescriptor with preResolved state from the matched skill entry.
|
|
*/
|
|
export function describeSkillReadGate(
|
|
tcc: ToolCallContext,
|
|
normalizer: PathNormalizer,
|
|
getActiveSkillEntries: () => SkillPromptEntry[],
|
|
): GateDescriptor | null {
|
|
const activeSkillEntries = getActiveSkillEntries();
|
|
|
|
if (tcc.toolName !== "read" || activeSkillEntries.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const inputRecord = toRecord(tcc.input);
|
|
const path = typeof inputRecord.path === "string" ? inputRecord.path : "";
|
|
if (!path) {
|
|
return null;
|
|
}
|
|
|
|
const normalizedReadPath = normalizer.comparableValue(path);
|
|
const matchedSkill = findSkillPathMatch(
|
|
normalizedReadPath,
|
|
activeSkillEntries,
|
|
normalizer,
|
|
);
|
|
|
|
if (!matchedSkill) {
|
|
return null;
|
|
}
|
|
|
|
const payload = buildSkillPathAskPayload(matchedSkill, path, tcc.agentName);
|
|
|
|
return {
|
|
surface: "skill",
|
|
input: { name: matchedSkill.name },
|
|
payload,
|
|
promptDetails: {
|
|
source: "skill_read",
|
|
agentName: tcc.agentName,
|
|
toolCallId: tcc.toolCallId,
|
|
toolName: tcc.toolName,
|
|
skillName: matchedSkill.name,
|
|
path,
|
|
accessIntent: accessFactsFromValue("skill", matchedSkill.name),
|
|
},
|
|
logContext: {
|
|
source: "skill_read",
|
|
toolCallId: tcc.toolCallId,
|
|
skillName: matchedSkill.name,
|
|
agentName: tcc.agentName,
|
|
path,
|
|
},
|
|
decision: {
|
|
surface: "skill",
|
|
value: matchedSkill.name,
|
|
},
|
|
preResolved: {
|
|
state: matchedSkill.state,
|
|
},
|
|
};
|
|
}
|