Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281import { emitExtensionDiagnostic } from "./extension-diagnostics";import type { ExtensionDiagnosticSink } from "../shared/extension-diagnostics";import { RpcTarget } from "cloudflare:workers";import * as Effect from "effect/Effect";import { skillScriptInput, type SkillScriptResult,} from "../shared/skill-execution";import { skillInvocationRequest, type SkillInvocationRequest, type SkillInvocationResult, type SkillScriptDefinition,} from "../shared/skill-invocation";import type { SkillIdentity } from "../shared/skill-management";import type { SkillListing } from "../shared/skills";import type { CapabilityReference } from "../shared/capability-policy";import { CapabilityDenied } from "./capability-policy";import { agentCall, agentValidation, type AgentFailure } from "./agent-io";import type { SkillExecutionPermissions } from "./skill-execution-permissions";import { skillIdentityOf } from "./skill-activity";import type { ValidatedSkillPackage } from "./skill-package";import type { McpInvocation } from "./mcp-invocation";import { runSkillScript, SKILL_SCRIPT_TIMEOUT_MS } from "./skill-script-runner";import { SkillScriptWorkspace } from "./skill-script-workspace";import { skillScriptTools } from "./skill-script-tools";
interface Context { diagnostics?: ExtensionDiagnosticSink; permissions: SkillExecutionPermissions; list: () => SkillListing[]; load: ( identity: SkillIdentity, ) => Effect.Effect<ValidatedSkillPackage | null, AgentFailure>; loader: WorkerLoader; external: ( reference: CapabilityReference, request: SkillInvocationRequest, ) => McpInvocation;}const failure = ( code: "script_failed" | "cancelled" | "timeout" | "invalid_input", message: string,): SkillScriptResult => ({ ok: false, result: null, stdout: "", stderr: "", exitCode: 1, truncated: false, error: { code, message },});
export class SkillInvocation extends RpcTarget { #controller = new AbortController(); #started = false; #startedAt = 0; constructor( private readonly context: Context, private readonly request: SkillInvocationRequest, private readonly definition: SkillScriptDefinition, ) { super(); } cancel() { this.#controller.abort(); } [Symbol.dispose]() { this.cancel(); }
private result( output: SkillScriptResult, files: { path: string; content: string }[] = [], ): SkillInvocationResult { const result: SkillInvocationResult = { kind: "skill-script", skill: { source: this.definition.skill.source, name: this.definition.skill.name, version: this.definition.version, fingerprint: this.definition.skill.fingerprint, }, path: this.definition.path, result: output, workspace: { files: [], truncated: false }, }; for (const file of files) { result.workspace.files.push(file); if ( new TextEncoder().encode(JSON.stringify(result)).byteLength > 65_536 ) { result.workspace.files.pop(); result.workspace.truncated = true; } } return result; }
private complete(result: SkillInvocationResult) { const output = result.result; emitExtensionDiagnostic(this.context.diagnostics, { operation: "skill-script", source: { kind: "skill", id: `${this.definition.skill.source}:${this.definition.skill.name}`, }, version: this.definition.version, fingerprint: this.definition.skill.fingerprint, startedAt: this.#startedAt, status: output.ok ? "completed" : output.error?.code === "cancelled" ? "aborted" : "error", ...(output.ok ? {} : { failure: output.error?.code === "timeout" ? "timeout" : output.error?.code === "cancelled" ? "cancelled" : "script", }), }); return result; }
async run( value: unknown, approvedOnce: boolean, ): Promise<SkillInvocationResult> { if (this.#started) return this.result( failure("script_failed", "This Skill invocation has already started"), ); this.#started = true; this.#startedAt = Date.now(); let timedOut = false; const deadline = setTimeout(() => { timedOut = true; this.cancel(); }, SKILL_SCRIPT_TIMEOUT_MS); const signal = this.#controller.signal; try { const result = await Effect.runPromise( this.context.permissions.run( this.request, { signal, approvedOnce: approvedOnce === true, conversationId: this.request.conversationId, toolCallId: this.request.toolCallId, }, (grant) => Effect.gen({ self: this }, function* () { const input = yield* agentValidation(() => { if ( new TextEncoder().encode(JSON.stringify(value)).byteLength > 32_768 ) throw new Error("Skill input exceeds 32 KiB"); return skillScriptInput.parse(value); }); const skill = yield* this.context.load(this.request.skill); grant.check("execute"); const source = skill?.files.find( (file) => file.path === this.request.path && file.encoding === "text", ); if (!skill || !source) throw new CapabilityDenied("unavailable"); const workspace = new SkillScriptWorkspace( grant, input.workspace, ); const result = yield* agentCall( () => runSkillScript({ loader: this.context.loader, skill: { ...skill.entry, sourceId: `flarebot-${this.request.skill.source}`, }, path: this.request.path, source: source.content, resources: (skill.entry.resources ?? []).filter( (resource) => resource.kind !== "script", ), input: input.input, signal, workspace, workspaceAccess: skill.permissions.workspace, tools: skillScriptTools({ requirements: skill.permissions, grant, signal, conversationId: this.request.conversationId, toolCallId: this.request.toolCallId, external: (reference) => this.context.external(reference, this.request), }), }), "Skill runner unavailable", ); grant.check("execute"); return this.result(result, result.ok ? workspace.snapshot() : []); }), ), { signal }, ); return this.complete(result); } catch (error) { return this.complete( this.result( signal.aborted ? failure( timedOut ? "timeout" : "cancelled", timedOut ? "Skill execution timed out" : "Skill execution was cancelled", ) : error instanceof CapabilityDenied ? failure("script_failed", error.message) : failure( "script_failed", "The Skill could not run with the current package, input or permissions", ), ), ); } finally { clearTimeout(deadline); this.cancel(); } }}
export class SkillScripts { constructor(private readonly context: Context) {} definitions(): SkillScriptDefinition[] { return this.context.list().flatMap((skill) => { const identity = skillIdentityOf(skill); return skill.scripts.flatMap((path) => { const metadata = this.context.permissions.describe(identity, path); return metadata && metadata.approval !== "never" ? [ { skill: identity, path, version: skill.version, requirements: skill.permissions, metadata, }, ] : []; }); }); } policy(value: Pick<SkillInvocationRequest, "skill" | "path" | "capability">) { const metadata = this.context.permissions.describe(value.skill, value.path); return metadata && metadata.id === value.capability.id && metadata.fingerprint === value.capability.fingerprint && metadata.source.kind === value.capability.source.kind && metadata.source.id === value.capability.source.id ? (metadata.approval ?? "ask") : "unavailable"; } invocation(value: unknown) { const request = skillInvocationRequest.parse(value); const definition = this.definitions().find( (definition) => definition.metadata.id === request.capability.id && definition.metadata.fingerprint === request.capability.fingerprint, ); if (!definition || this.policy(request) === "unavailable") throw new CapabilityDenied("unavailable"); return new SkillInvocation(this.context, request, definition); }}