{
  "markdown": "# Floret\n\nFloret is a reusable Go engine for interactive AI agents. It owns the model\nloop and the complete admitted Agent lifecycle: canonical messages, threads,\nturns, runs, tools, approvals, todos, artifacts, context, SubAgents, recovery,\nprovider state, prompt cache, and observable execution facts.\n\nThe host application owns product UI, credentials, provider profiles, resource\nauthorization, routing, read state, uploads before admission, and transport\ndiagnostics. It must not persist or rebuild a second queryable Agent lifecycle.\n\nFloret is not a graph workflow framework, a multi-agent orchestrator, or a\nproduct persistence layer.\n\n## Install\n\nBuild with Go 1.27.1.\n\n```bash\ngo get github.com/floegence/floret/v7@v7.3.2\n```\n\nProduction integrations must resolve the published module. Do not use a local\n`replace`, `go.work`, or sibling repository path. Earlier major versions remain\navailable only from their published tags; v7 does not restore retired facades.\n\n## Quick Start\n\nEvery Agent uses one explicit `provider.Gateway`. Floret allocates durable\nthread, turn, and run identities; an application supplies only a stable\n`identity.LogicalRequestID` for each logical mutation. This production example\nuses the official OpenAI-compatible Gateway and SQLite:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"os\"\n\n    \"github.com/floegence/floret/v7/config\"\n    \"github.com/floegence/floret/v7/provider\"\n    \"github.com/floegence/floret/v7/runtime\"\n    \"github.com/floegence/floret/v7/storage\"\n)\n\nfunc main() {\n    ctx := context.Background()\n    gateway, err := provider.NewOpenAICompatible(provider.OpenAICompatibleOptions{\n        Provider: \"openai\", Model: \"gpt-4.1-mini\",\n        BaseURL: \"https://api.openai.com/v1\", APIKey: os.Getenv(\"OPENAI_API_KEY\"),\n        StateCompatibilityKey: \"openai:gpt-4.1-mini:chat-completions:v1\",\n        Capabilities: provider.Capabilities{\n            Reasoning: provider.ReasoningUnsupported,\n            AttachmentPayload: provider.AttachmentDescriptors,\n        },\n    })\n    if err != nil { panic(err) }\n    agent, err := runtime.NewAgent(config.AgentConfig{\n        Profile:      config.AgentProfile{ID: \"assistant\", Name: \"Assistant\"},\n        SystemPrompt: \"Answer clearly and concisely.\",\n        Context:      config.ContextPolicy{ContextWindowTokens: config.DefaultContextWindowTokens},\n    }, gateway)\n    if err != nil {\n        panic(err)\n    }\n\n    host, err := runtime.Open(ctx, runtime.Options{Storage: storage.SQLite(\"floret.db\")})\n    if err != nil {\n        panic(err)\n    }\n    defer func() {\n        if err := host.Shutdown(context.Background()); err != nil {\n            panic(err)\n        }\n    }()\n\n    service, err := host.ThreadService(runtime.AgentFactoryFunc(func(context.Context, runtime.AgentRequest) (*runtime.Agent, error) {\n        return agent, nil\n    }))\n    if err != nil {\n        panic(err)\n    }\n    created, err := service.Create(ctx, runtime.CreateThreadInput{RequestKey: \"create-conversation-42\"})\n    if err != nil {\n        panic(err)\n    }\n    _, err = service.Send(ctx, runtime.SendInput{ThreadID: created.ThreadID, RequestKey: \"send-message-42\", Input: runtime.UserInput{Text: \"Hello\"}})\n    if err != nil {\n        panic(err)\n    }\n}\n```\n\nHosts may also set `runtime.SendInput.SupplementalContext` for material that is\nneeded only by the current provider turn. Floret validates and renders that\ncontext for the provider without adding a second canonical conversation\nmessage. The pre-dispatch checkpoint records only that an ephemeral overlay was\npresent; it never stores the overlay, its payload hash, provider continuation,\nor overlay-derived request measurements.\n\nHosts that need immutable execution metadata may construct an Agent with\n`runtime.WithAgentRunLabels`. Correlation labels remain observable, while the\nopaque Host map reaches provider requests, permission checks, and local tool\ninvocations without becoming durable conversation state.\n\nRun it with `OPENAI_API_KEY=... go run ./cmd/examples/openai-sqlite`. The complete\nexample also reads the authoritative assistant projection. `florettest` remains\ntest-only; use it for deterministic provider scripts and `florettest.NewIDSource`\nfor deterministic lifecycle identities.\n\n## Public Packages\n\n| Package | Responsibility |\n| --- | --- |\n| `identity` | Thread, turn, run, prompt-scope, trace, logical-request, and artifact identities |\n| `config` | Provider-neutral Agent profile, prompt, context, and reasoning policy |\n| `runtime` | Immutable Agent construction, durable Host lifecycle, commands, queries, and subscriptions |\n| `observation` | Sanitized runtime events and host-facing projections |\n| `tools` | Local tool definitions, permissions, resources, effects, and results |\n| `tools/webfetch` | Secure public-text HTTP/HTTPS fetch tool with fixed network and output limits |\n| `provider` | Model Gateway contract and official provider constructors |\n| `storage` | Opaque storage values and official memory and SQLite constructors |\n| `storage/spi` | Advanced physical storage implementation contract |\n| `florettest` | Scripted gateways and public conformance suites for tests only |\n\nOrdinary applications use `identity`, `config`, `runtime`, `observation`,\n`tools`, the official `provider` constructors, and opaque `storage.Source`\nvalues. Custom provider transports and physical storage implementations are\nadvanced integration surfaces with separate conformance suites. Downstream\ncode must never import `internal/*`.\n\nTool definitions may provide `InvalidActivity` when a host needs to preserve a\nsafe display label from a parseable JSON object that fails the input schema.\nFloret uses that callback only for presentation: the invalid invocation still\nfails closed before permission, effect dispatch, and handler execution.\n\nQuestion activity may include host-authored answer summaries for completed\nprompts. A secret answer is represented only by `Redacted: true`; Floret\nrejects a redacted answer that also carries values. These fields are display\ndata, not an alternate input-response or durable message authority.\n\nStructured activity may include bounded, ordered `Rows` containing\nhost-sanitized text, Markdown, or code. Floret validates and preserves these\ndisplay rows without interpreting product tools or accepting arbitrary JSON\npayloads.\n\nActivity presentation is cumulative for one tool invocation. A result may add\nterminal status and output, while non-empty display facts from the matching\ntool call remain available in events, canonical views, and reopened threads.\n\n`tools.TerminalActivityPayload` adds optional operation, sent-byte count,\noutput cursors, remaining-output flag, total bytes, public execution location,\nand timeout facts. Hosts author the label and description and retain only safe\ncommand display text; raw stdin and credentials are never display fields.\nRead cursor snapshots replace their cursors and `has_more` together, so a final\npage can clear the flag. Status-only updates preserve the prior snapshot.\n\nSubAgent management activity uses a dedicated operation payload that preserves\nthe exact action, ordered child targets, and bounded outcome counts. The\nexisting single-SubAgent payload remains the durable child-thread fact; hosts\ndo not need to infer management actions from labels or collapse multi-child\nresults.\n\n`tools/webfetch.New` supplies the product-neutral `web_fetch` implementation.\nIt performs GET-only public HTTP/HTTPS reads, revalidates redirects, DNS, and\ndial targets, rejects non-text bodies, and returns Markdown or text under fixed\nlimits. Its typed Activity carries the requested URL, response metadata, a\n2,000-character preview; complete content remains in the tool result and\nartifact. It does not discover or request page icons. Hosts own static tool\niconography, visibility, current product permission policy, and UI.\nAuthentication, custom headers, non-GET requests, binary downloads, and browser\nrendering remain separate host capabilities.\n\n## Runtime Boundary\n\n`runtime.Host` belongs in the composition root. `Host.ThreadService` returns the\nsingle typed lifecycle boundary. Title snapshots expose `Title`, `TitleStatus`, and\n`TitleGeneration`; hosts order them independently of body updates and activity.\nSee the [title snapshot contract](okf/api/runtime.md#title-snapshots). Its `Create`, `Fork`, `Delete`, `SetTitle`,\n`List`, `View`, `History`, `Send`, `Respond`, `Cancel`, `Retry`,\nqueue, import, and `Subscribe` methods all operate on stable thread and request\nidentities. Child agents are ordinary child threads with explicit parent\nidentity, so they use the same current-view and command contracts.\n\nEach thread has one in-memory runtime owner. `Send` first commits canonical turn\nacceptance, then publishes and returns the user item and active current view\nbefore provider dispatch. The canonical journal is the only durable fact\nsource. Provider and tool I/O execute outside the thread lock.\n`Cancel` is idempotent for every known thread. It commits the terminal turn\nbefore returning, releases pending interactions, and fences late provider or\ntool output without waiting for those goroutines to exit. If an irreversible\neffect outcome cannot be confirmed, Floret atomically fails the turn with\n`effect_outcome_unknown`, closes every unfinished tool and interaction, clears\nprovider continuation, and never replays the effect.\n`Respond` resolves the matching approval or input interaction in place.\nPublic Ask User answers become one canonical user message and remain in every\nlater provider request. Secret answers are sent only to the current continuation;\nthe journal and later context retain a redacted marker, never the secret value.\n\n`runtime.NewAgent` resolves the Agent profile, system prompt, Gateway, tools,\ncapabilities, reasoning policy, and execution policy. The first provider\ncheckpoint freezes that complete execution surface for one Turn. Ask User,\nordinary tool loops, retries, and restart recovery reuse it exactly. Provider\nnatural stop completes the Turn; there is no second completion protocol.\nProvider credentials and editable profile sources remain in the host.\n\nAn `AgentFactory` may select a new system prompt, tool surface, provider, model,\nor reasoning policy for each new Turn. The canonical conversation remains\nappend-only. Floret maintains a content-addressed render lineage for each exact\nexecution surface, clears opaque continuation state when the surface changes,\nand compacts only when explicitly requested or when the selected model's\ncontext window needs it. A waiting interaction, tool continuation, retry, or\nrestart remains frozen to the surface recorded for that Turn. Historical tool\ncalls remain readable when their definitions are removed; a new call to an\nunavailable tool returns a safe ordinary tool result and the model loop\ncontinues.\n\nCurrent views contain one Floret-ordered sequence of directly renderable user,\nthinking, assistant, tool, and interaction items, plus pending interactions and\nthe accepted queue. Each item has a stable ID and ordinal; live deltas grow the\nsame item in place, and tool approval, dispatch, and result state update the\noriginal tool item. Canonical reload derives the same sequence without a\npresentation ledger or draft mirror fields.\nEvery item and interaction carries its exact `TurnID` and `RunID`, so multi-turn\nhistory and same-turn continuation never borrow identity from the current run.\n`ThreadView.RunID` identifies only the current execution; hosts must never use\nit to fill historical items. `RunProgress` is the actor-owned, process-local phase\nfor an advancing run and is absent while awaiting interaction or after the run\nsettles.\n`ViewVersion` is process-local notification ordering, not a durable replay\ncursor. Production hosts leave `runtime.Options.IDSource` nil; deterministic\nidentity injection belongs to `florettest.NewIDSource`.\n\n## Consistent Reads\n\n`ThreadService.View` returns one complete replaceable current view.\nThe value returned by `Host.ThreadService` also implements\n`ThreadContextReader`; `Context` returns Floret's canonical context policy,\nusage, and one latest lifecycle record per compaction operation, including\nterminal state restored after runtime restart. The snapshot also exposes\nconversation-wide disjoint input, output, cache-read, and cache-write totals\nfolded from canonical final provider usage records.\nForked snapshots retain historical Turn and Run identity while reporting the\ndestination Thread identity. Floret owns this projection and automatically\nmigrates affected v8 stores; hosts do not patch context records.\nEach successfully committed final `provider_usage` runtime event also carries\n`ThreadUsageTotals`. It is the live form of the same canonical fold; projected\nrequests, stream-only usage, rejected attempts, and failed writes omit it.\n`ThreadService.Subscribe` publishes workspace summary and current-view updates;\nreconnecting clients refresh summaries and the currently visible view. There is\nno durable cursor, replay ledger, materialized projection, or second lifecycle\nauthority.\n\n## Storage\n\nFor ordinary hosts, `storage.Source` is an opaque value consumed exclusively by\n`runtime.Open`:\n\n```go\nruntime.Open(ctx, runtime.Options{Storage: storage.Memory()})\nruntime.Open(ctx, runtime.Options{Storage: storage.SQLite(\"agent.db\")})\n```\n\nHosts that present startup readiness may observe Floret's product-neutral\nstorage phases without reading physical records:\n\n```go\nhost, err := runtime.Open(ctx, runtime.Options{\n    Storage: storage.SQLite(\"agent.db\"),\n    StartupProgress: runtime.StartupProgressFunc(func(phase runtime.StartupPhase) {\n        // Present migrating or verifying without exposing stored content.\n    }),\n})\n```\n\nThe callback is synchronous and must return promptly. Legacy stores report\n`migrating` followed by `verifying`; fresh and current stores report only\n`verifying`. A returned `Host` is ready, and a failed migration remains atomic.\n\nApplications cannot use a Source as a lifecycle query path. Teams implementing\na physical backend use the advanced `storage/spi` contracts and their\nconformance suite. SPI records remain opaque Floret data; a backend must not\ndecode them into a second Agent model. Memory, SQLite, and third-party backends\nall run the same Floret-owned domain kernel.\n\nNew SQLite stores use incremental auto-vacuum so deleted pages can be reclaimed\nwithout rebuilding the database. A host that owns an older SQLite file may call\n`storage.MaintainSQLite` before `runtime.Open`. The maintenance boundary checks\nthe exact Floret physical schema and database integrity, refuses an open\nruntime, and uses SQLite's native `VACUUM` or `incremental_vacuum`; it never\ncopies records or exposes their contents.\n\n### Coordinated storage startup and restore\n\nHosts with multiple stores can call `runtime.InspectSQLite` before any writable\nopen and `storage.BackupSQLite` while all writers are stopped. Inspection checks\nthe supported migration path in memory without creating a runtime Host. A backup\nincludes committed WAL records and never overwrites its destination.\n\nOpen with `runtime.Options{Storage: source, DeferExecution: true}` when product\nstores or authorization must be prepared first. Reads and pending-input import\ncannot start execution until `host.Activate(ctx)` succeeds. Default startup\nremains automatic. `ErrExecutionDeferred` identifies commands attempted before\nactivation; `ErrStoreTooNew` identifies a newer logical storage contract.\n\nFor a restored snapshot, call `host.PrepareRestore(ctx)` on the staged, deferred\nHost before activating or publishing the storage set. It stops unfinished turns,\nresolves old interactions, and removes queued work from execution while exposing\nits original input through `ThreadView.RestoredInputs`. `ErrRestoredTurn` prevents\nretrying a stopped turn. Users must submit a new request under current authority.\nRestore does not undo external side effects. The application owns consistent\nmulti-store snapshots, confirmation, retention, and recoverable file replacement.\n\n## Source Of Truth\n\nFloret exclusively owns admitted messages and references, thread/turn/run\nlifecycle, titles, approvals, todos, tool invocation and outcome, pending-work\nsettlement, artifacts, control signals, context and compaction, provider\nledgers and state, prompt cache, SubAgent hierarchy, and Activity projections.\n\nHosts may persist product authorization and audit, routing, credentials,\neditable persona sources, resource catalogs, read state, unadmitted commands,\nupload staging, and transport diagnostics. Those records must not contain a\nserialized Floret DTO or support reconstruction of Agent state. Canonical\nmessage references are opaque durable facts; rich material needed only for the\ncurrent provider turn belongs in `SupplementalContext` and never becomes\nconversation history or continuation state.\n\n## Shutdown\n\n`Host.Shutdown(ctx)` stops admission, cancels Host-managed provider and tool\nexecution, waits for it to finish, and then closes storage. If the context\nexpires, Shutdown returns `ctx.Err()` and Host remains closing; a later call\ncontinues waiting. After completion, every retained handle returns\n`ErrHostClosed`.\n\n## DeepSeek Responses\n\nUse `provider.NewDeepSeek(provider.DeepSeekOptions{...})` for DeepSeek V4 Pro\nand Flash. Set `Model`, `BaseURL` (normally `https://api.deepseek.com`), `APIKey`,\nand an explicit `StateCompatibilityKey`. The gateway always calls `/responses`,\nstreams text and reasoning, and accepts the native hosted tool\n`provider.HostedToolDefinition{Name: \"web_search\", Type: \"web_search\"}`.\nFor durable Agents, declare it through `runtime.WithAgentHostedTools`\nso Engine admission and provider requests\nshare the same tool surface. Short requests without that surface do not search.\n\nWeb Activity preserves `Operation` (`search`, `open_page`, `find_in_page`),\n`Query` (ordered queries separated by newlines), `URL`, `Pattern`, and source\n`Title`, `URL`, and `Snippet`. `ResultsProvided` distinguishes an explicitly\nreturned empty list from unavailable details. An empty operation remains\nunknown. Hosts render these facts from canonical Activity, including after\nrestart; answer citations are not per-call search results. These additive v7.4\ncontracts serve Redeven's shared Flower UI and other public Activity consumers.\n\nDeepSeek is stateless. Floret retains provider-native response items in opaque\nstate, validates them against the canonical conversation, and returns the full\ninput history on each call, including search receipts and reasoning. Hosts must\nnot inspect or rebuild this state. Supplemental-context Turns retain their\nexisting no-continuation-state privacy boundary. Prepared estimates include the complete wire\npayload. Missing terminal events fail; truncated responses continue through the\nnormal runtime limit policy. The existing `NewOpenAICompatible` constructor\ncontinues to select Chat Completions explicitly.\n\n## Development\n\n```bash\nGOWORK=off go test ./...\nGOWORK=off go vet ./...\nGOWORK=off go test -race ./...\nscripts/check_candidate_release_adoption.sh\n```\n\nRepository workflow and compatibility rules are defined in [AGENTS.md](AGENTS.md).\nArchitecture and maintenance knowledge lives in [okf/](okf/).\n",
  "bytes": 19276,
  "sha": "9c8b77bbf6c1d52ff26daf1055ef8bf4f54ee0a98e8b17508b0f631717eef470",
  "repo_slug": "floegence/floret",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_floegence_floret_okf_index_md_f1f334f8/readme"
}