Documentation
¶
Overview ¶
Package aikit is what every AI adapter does the same way, whatever its provider: the prompts, the tools a model is given and their schemas, the budgeted reader a model reads the repository through, and what a tool call does. An adapter translates these into its provider's own request types and runs the conversation; nothing here speaks to a provider.
One copy, so the Anthropic, OpenAI and local adapters ask the same questions under the same rules (R-332 – R-334) and are refused the same way by core when a model breaks one. A second copy of a prompt is a copy that drifts.
Like every package under internal/adapter, this imports adapter/api and nothing of core's authorization, audit or state (R-027).
Index ¶
- Constants
- Variables
- func Call(name, input string, src *Reader) (string, bool)
- func Findings(input string, src *Reader, model string) (api.ScreenResult, error)
- func JSONBlock(v any) string
- func KeyStep(link api.Link, do ...api.Action) api.Step
- func Limit[T int | int64](asked, own T) T
- func ModelStep(links []api.Link, do ...api.Action) api.Step
- func Preloaded(src *Reader, known []string) string
- func SystemPrompt(fn api.AIFunction) string
- func UserPrompt(fn api.AIFunction, req api.ScreenRequest) string
- type Looker
- type Reader
- type Task
- type Tool
Constants ¶
const ( ToolFindPeople = "find_people" ToolFindApps = "find_apps" ToolFindGroups = "find_groups" // MaxLookups is the most lookups one conversation may make. Past it a // lookup is answered with a request to submit, not run, so a model that // keeps searching ends the conversation rather than growing it. MaxLookups = 10 )
The lookup tools (O-54): how a model drafting access or searching the audit log finds the people, apps and groups a request names, instead of being handed every one. Each runs a callback core passed in the request, as the person who asked; nothing here reads state (R-027).
const ( ToolListFiles = "list_files" ToolReadFile = "read_file" ToolSubmitFindings = "submit_findings" // ToolSubmit is the one tool the administrative functions get. ToolSubmit = "submit" )
The tools a repair, an answering or a revision call gets: two to read the repository, one to answer.
Answering through a tool rather than in prose is deliberate. The schema is the closed set from design 10 §3, so a malformed amendment is rejected before it reaches Pando, and the shape core validates is the shape the model was given. Parsing amendments out of prose would mean two descriptions of the same structure, kept in step by hand.
const AnswerThroughTool = " Answer only by calling the submit tool, once. Do not answer in prose."
AnswerThroughTool is added to every task's system prompt. The call is asked for rather than forced: current models refuse forced tool use.
const LookupNote = "The lists below are not every account, app or group: look up anyone or anything the " +
"request names with the find tools, and use the IDs they return. Never make up an ID. If a lookup " +
"finds nobody, leave them out and say so."
LookupNote is what a prompt says about the lookup tools, when it has them.
const MatchNote = "The lists below are not every account, app or group: they are the ones whose names " +
"match words in the request. If someone or something the request names is not listed, leave it out " +
"and say so; never make up an ID."
MatchNote is what a prompt says about lists core pre-searched, for an adapter without the lookup tools.
const MaxFileBytes = 64 << 10
MaxFileBytes is the most of one file a model is shown. Longer files are truncated, and say so.
const Voice = "Write for the person who asked, in plain sentences. Be specific and self-contained: " +
"someone reading only your answer should understand it. No apology, no exclamation mark, " +
"no \"Error:\" prefix, and do not restate the question."
Voice is the house style every answer here is held to (R-105), said once.
Variables ¶
var ErrBudget = errors.New("budget spent")
Functions ¶
func Call ¶
Call runs one read tool and says what to hand back: the text, and whether it is an error.
A budget refusal comes back as an ordinary result rather than an error, so the model can submit what it has instead of the whole screening being lost over one file too many. That is the difference between a bounded screening and a failed one.
func Findings ¶
Findings reads a submit_findings call's input.
Parsed rather than matched on the raw string: escaping in a tool input is the model's to choose, and string matching on it is how that bites.
func Limit ¶
Limit takes the lower of what core asked for and what the adapter will do. Neither side raises the other's (design 10 §2).
func Preloaded ¶
Preloaded reads the files an earlier call on this proposal read, and hands them over at the start: the model begins knowing what it knew last time, rather than listing and reading its way back there one round trip at a time. Read through the budgeted reader, so they count as reads and are recorded as sent (R-337); one the budget refuses, or that is gone, is left out.
func SystemPrompt ¶
func SystemPrompt(fn api.AIFunction) string
SystemPrompt returns the job for fn, and the rules core will enforce anyway.
Stating the rules twice is not redundancy. Core refuses an amendment that breaks one of these (design 10 §3), so a model that has not been told is a model whose work is thrown away — the refusal is correct and the call is wasted. Telling it here is what turns a refusal into a rarity.
func UserPrompt ¶
func UserPrompt(fn api.AIFunction, req api.ScreenRequest) string
UserPrompt is the proposal, rendered.
Types ¶
type Looker ¶
type Looker struct {
// contains filtered or unexported fields
}
Looker runs the lookup tools for one conversation, counting them.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader is the repository, bounded.
Every read goes through here rather than straight to the SourceView, for two reasons that are not the same. The budget (R-339) is one: a screening has a ceiling in files and bytes and something has to hold the running total. The other is that this is the list of what left the host, which R-337 says the audit event carries — and a count kept beside the reads is a count that cannot disagree with them.
func (*Reader) Glob ¶
Glob lists paths without counting against the file budget.
Listing is not reading. The budget exists to bound what content leaves the host, and a list of names is how the model decides which of them to spend the budget on — charging for it would make an efficient screening impossible.
type Task ¶
type Task struct {
System string
User string
Tool Tool
// Lookup, when set, is what the lookup tools run (O-54).
Lookup *api.Lookup
}
Task is one administrative request: what the model is told, what it is asked, and the tool it answers through.
func AccessTask ¶
func AccessTask(req api.AccessRequest) Task
AccessTask drafts a role and, optionally, a group (R-343).
func AuditSearchTask ¶
func AuditSearchTask(req api.AuditSearchRequest) Task
AuditSearchTask turns a question into one audit filter (R-345).
func AuditSummaryTask ¶
func AuditSummaryTask(req api.AuditSummaryRequest) Task
AuditSummaryTask summarizes the records core found (R-345).
func PolicyTask ¶
func PolicyTask(req api.PolicyRequest) Task
PolicyTask proposes changes to host policy (R-344).
func ReferenceTask ¶
func ReferenceTask(req api.ReferenceRequest) Task
ReferenceTask answers from the generated reference (R-346).
type Tool ¶
type Tool struct {
Name string
Description string
// Properties and Required are the input schema's; the schema is always an
// object.
Properties map[string]any
Required []string
// Strict asks a provider that can to validate the input against the
// schema before the call reaches Pando.
Strict bool
}
Tool is one tool, as every provider's tool definition needs it: a name, a description, and a JSON Schema object for its input.
func LookupTools ¶
LookupTools are the tools l offers: one per lookup the person may make.
func ScreenTools ¶
ScreenTools are the tools for fn: list, read, and submit findings.