Documentation
¶
Overview ¶
Package frege is a small, dependency-free Go client for the Frege HTTP API.
Frege turns each project's OpenAPI spec into a set of tools and runs them against the upstream API with the right credential injected. This client lets your own code — a Telegram bot, a cron job, a backend service — call those tools directly, with no AI model in the loop.
Auth in one paragraph ¶
Use a project API key. Mint one in the dashboard under Project → API keys; it is shown once and starts with frege_sk_. It is scoped to that one project, it does not expire, and it needs no refresh machinery:
c := frege.New(frege.StaticToken("frege_sk_…"))
res, err := c.InvokeTool(ctx, projectID, "get_account_profile", nil)
A Frege USER's access token works too, for code acting as a person rather than as a service. Those are short-lived, so sign in once with an email code (see the bootstrap example) and let a *RefreshingToken trade the refresh token for new access tokens. Refresh tokens ROTATE — every refresh invalidates the old one — so persist each new pair via OnRefresh or a restart will present a token the server no longer accepts.
tok := frege.NewRefreshingToken("", storedRefreshToken,
frege.WithOnRefresh(func(access, refresh string) { save(refresh) }))
c := frege.New(tok)
Acting as one customer ¶
On a project whose end customers each sign in with their own upstream account, AsClient names WHICH customer's credential to spend. One key, one agent, any customer — and both parties land in the audit trail.
res, err := c.InvokeTool(ctx, projectID, "get_account_profile", nil,
frege.AsClient(customerID))
Index ¶
- Constants
- func SendMagicCode(ctx context.Context, baseURL, email string) error
- type APIError
- type Client
- func (c *Client) InvokeTool(ctx context.Context, projectID int64, toolName string, args map[string]any, ...) (*ToolResult, error)
- func (c *Client) ListOperations(ctx context.Context, projectID int64) ([]Operation, error)
- func (c *Client) ListProjects(ctx context.Context, orgID int64) ([]Project, error)
- type InvokeOption
- type Operation
- type Option
- type Project
- type RTOption
- type RefreshingToken
- type Session
- type StaticToken
- type TokenSource
- type ToolResult
- type User
Constants ¶
const ( StageStaging = "staging" StageLive = "live" )
Client talks to one Frege environment as one user. The two environments every project has. A project-scoped call is answered by one of them, and the choice is carried in a header.
const DefaultBaseURL = "https://frege.io"
DefaultBaseURL is Frege's production API. Use https://frege.uz for dev.
const StageHeader = "X-Frege-Stage"
StageHeader carries the environment on every project-scoped request.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type APIError ¶
type APIError struct {
StatusCode int
Code string
Message string
Fields map[string]string
RequestID string
}
APIError is a non-2xx response from Frege itself (not from the upstream API).
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
func New ¶
func New(tokens TokenSource, opts ...Option) *Client
New builds a Client. tokens supplies the bearer for each call — usually a *RefreshingToken built from a stored refresh token.
func (*Client) InvokeTool ¶
func (c *Client) InvokeTool(ctx context.Context, projectID int64, toolName string, args map[string]any, opts ...InvokeOption) (*ToolResult, error)
InvokeTool runs one tool and returns the raw upstream response. args are keyed by the tool's input schema; pass nil for a tool that takes none.
The returned ToolResult.StatusCode and Body are the UPSTREAM's own: a 404 there means the upstream answered 404, not that the tool is missing. A missing tool, a bad argument, or an auth problem is returned as an *APIError instead.
func (*Client) ListOperations ¶
ListOperations returns the tools generated from the project's active spec: their names, HTTP method/path, summary, and JSON input schema.
type InvokeOption ¶
type InvokeOption func(*invokeBody)
InvokeOption tunes a single InvokeTool call.
func AsClient ¶
func AsClient(clientID int64) InvokeOption
AsClient runs the tool with one connected customer's stored credential instead of the project's own. Required wherever the project has no shared project-level credential.
The id comes back from enrolling the customer. If you did not keep it, use AsCustomer instead — it is almost always the better call.
func AsCustomer ¶
func AsCustomer(reference string) InvokeOption
AsCustomer runs the tool as the customer you enrolled under this reference.
The reference is the external_ref you supplied when connecting them: the phone number, the chat id, whatever your channel already knows them by. That is the point — a bot holds a chat id, not a row id, and keeping a table that maps one to the other means running a database whose only job is to remember something Frege already knows.
It is a LABEL and not a secret. It authorises nothing on its own: your API key is what says you may spend this project's customers' credentials, and it could spend this one by id regardless. What the customer's own sign-in proved, it proved at enrolment.
One caveat worth knowing before you rely on it. The same person enrolled twice — once in a browser, once through your bot — is two customers holding two different upstream credentials, because linking them needs a verified claim common to both and Frege will not guess. A reference that names both is REFUSED rather than resolved, since picking one would spend an account you did not name. Use AsClient with the id when that happens.
type Operation ¶
type Operation struct {
ID string `json:"id"`
ToolName string `json:"tool_name"`
Method string `json:"method"`
Path string `json:"path"`
Summary string `json:"summary"`
Description string `json:"description"`
Tags []string `json:"tags"`
InputSchema map[string]any `json:"input_schema"`
}
Operation is one tool generated from the project's spec.
type Option ¶
type Option func(*Client)
Option configures a Client.
func WithBaseURL ¶
WithBaseURL points the client at a specific environment (default DefaultBaseURL).
func WithHTTPClient ¶
WithHTTPClient supplies your own *http.Client (timeouts, proxy, and so on).
func WithStage ¶
WithStage picks the environment every project-scoped call is answered by: frege.StageStaging or frege.StageLive.
OMITTING THIS MEANS LIVE. That is the server's default, not this client's choice, and it is the one thing worth knowing before pointing a test at a real deployment: a run that means to exercise staging and never sets a stage reads production's spec and spends production's credential, and every response looks perfectly normal.
An API key is bound to ONE environment when it is issued, so a key and a stage that disagree fail rather than crossing over. That is the server protecting you, not this option.
type Project ¶
type Project struct {
ID int64 `json:"id"`
OrgID int64 `json:"org_id"`
Role string `json:"role"`
Slug string `json:"slug"`
Name string `json:"name"`
Description string `json:"description"`
UpstreamBaseURL string `json:"upstream_base_url"`
MCPURL string `json:"mcp_url"`
WritePolicy string `json:"write_policy"`
}
Project is one Frege project the user can reach.
type RTOption ¶
type RTOption func(*RefreshingToken)
RTOption configures a RefreshingToken.
func WithOnRefresh ¶
WithOnRefresh registers a callback invoked with each new (access, refresh) pair. Use it to persist the rotating refresh token.
func WithRefreshBaseURL ¶
WithRefreshBaseURL sets the environment the refresh call is made against (default DefaultBaseURL). Use the same base URL as the Client.
func WithRefreshHTTPClient ¶
WithRefreshHTTPClient supplies the *http.Client used for refresh calls.
type RefreshingToken ¶
type RefreshingToken struct {
// OnRefresh, if set, is called with each new (access, refresh) pair right
// after a successful refresh. Persist the refresh token here.
OnRefresh func(access, refresh string)
// contains filtered or unexported fields
}
RefreshingToken keeps a short-lived access token alive by trading a refresh token for a new one whenever the access token is rejected. It is safe for concurrent use.
Refresh tokens ROTATE: every refresh returns a new refresh token and the old one stops working. Set OnRefresh to persist the new pair, or a restart will fall back to a refresh token the server no longer accepts.
func NewRefreshingToken ¶
func NewRefreshingToken(accessToken, refreshToken string, opts ...RTOption) *RefreshingToken
NewRefreshingToken builds a token source from a stored refresh token. Pass an empty accessToken to force a refresh on first use.
type Session ¶
type Session struct {
Token string `json:"token"`
RefreshToken string `json:"refresh_token"`
User User `json:"user"`
}
Session is what a sign-in returns: a short-lived access token, a rotating refresh token, and the signed-in user.
type StaticToken ¶
type StaticToken string
StaticToken is a TokenSource that always returns the same token. Use it when you already hold a valid access token and manage its lifetime yourself.
type TokenSource ¶
TokenSource yields the bearer token to send on each request.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
bootstrap
command
Command bootstrap performs a one-time Frege sign-in and prints the refresh token your service should store.
|
Command bootstrap performs a one-time Frege sign-in and prints the refresh token your service should store. |
|
telegrambot
command
Command telegrambot is a minimal Telegram bot that runs one Frege tool for every message it receives and replies with the result.
|
Command telegrambot is a minimal Telegram bot that runs one Frege tool for every message it receives and replies with the result. |