Your Own Capabilities: Implementing one
● Intermediate3 min
An implementation is an ordinary type with type Name: Capability, giving a body to each method.
An implementation may need capabilities of its own. This one reads files, and only inside ./inbox, so the agent using it can't read anything else, whatever name it is given:
use std.fs
type InboxError = Missing(name: String) | Denied(reason: String)
capability Inbox {
fn read(name: String) -> String ! InboxError
}
type InboxFolder: Inbox {
fn read(self, name: String) -> String ! InboxError uses Fs.read("./inbox") {
fs.read_text("./inbox/{name}") catch e => match e {
FsError.Denied(path) => fail InboxError.Denied(reason: "outside ./inbox: {path}"),
_ => fail InboxError.Missing(name: name),
}
}
}
agent Summarizer {
can Inbox.read, Console
on summarize(name: String) ! InboxError {
const text = try Inbox.read(name)
print("{name}: {text.len()} characters")
}
}
fn main() ! Error {
try fs.create_dir("inbox")
try fs.write_text("inbox/note.txt", "Call the bank on Monday.")
try fs.write_text("passwords.txt", "do not share")
const bot = Summarizer.start(Inbox: InboxFolder())
bot.summarize("note.txt") catch e => print("failed: {e}")
bot.summarize("../passwords.txt") catch e => print("failed: {e}")
}The program ran and printed:
kavach run uc-files.kav
note.txt: 24 charactersfailed: Denied(reason: "outside ./inbox: ./inbox/../passwords.txt")
A real payments implementation would need Net to reach the bank. An agent is granted a capability whole (can Payments) or one method at a time (can Inbox.read).