import * as smoltalk from "smoltalk"; import type { DecisionAnswer, ThinkingBlock, TokenAlternative } from "smoltalk"; import { type ResultValue } from "../runtime/result.js"; import type { ModelUsage } from "../runtime/utils.js"; import type { UsageKind } from "../runtime/invocationUsage.js"; import type { RuntimeContext } from "../runtime/state/context.js"; import type { StateStack, TurnScope } from "../runtime/state/stateStack.js"; import type { ThreadStore } from "../runtime/state/threadStore.js"; /** * std::thread TS implementations for the context-injected builtins * registered in `lib/codegenBuiltins/contextInjected.ts`. The agency- * side wrappers in `stdlib/thread.agency` call these without any of * the prefix args; the TypeScript builder prepends `__ctx`, * `__stateStack`, and `__threads` at every context-injected call * site. * * - Message builtins (`*Message`) push onto the active thread of the * caller's `__threads` store. They ignore `_stack` and use * `threads.getOrCreateActive()` so messages injected before the first * `llm()` call still land on a real thread (rather than being * silently dropped by `threads.active()?.push(...)`). * - Cost / token builtins (`getCost`, `getTokens`) read the per-branch * accumulator from the caller's `__stateStack` (which has been * seeded by `Runner.runForkAll` / `runRace` to inherit parent * totals). They ignore `_ctx` and `_threads`. * * See docs/superpowers/specs/2026-05-20-thread-builtins-and-stdlib- * design.md for the per-branch cost model. */ export declare function __internal_systemMessage(_ctx: RuntimeContext, _stack: StateStack, threads: ThreadStore, msg: string): Promise; /** When a message pushed from Agency code is removed: "never", or when * the next llm() call on the thread returns. */ export type MessageExpiry = "never" | "llmCall"; /** ALS-reading replacement for `__internal_systemMessage`. `label` is an * observability-only debug tag shown in statelog; "" means unlabeled and * is normalized to null. Never sent to the provider. */ export declare function _systemMessage(msg: string, label?: string, expires?: MessageExpiry): Promise; export declare function __internal_userMessage(_ctx: RuntimeContext, _stack: StateStack, threads: ThreadStore, msg: smoltalk.UserContentInput): Promise; /** ALS-reading replacement for `__internal_userMessage`. Accepts a plain * string or an array of text strings and image()/file() attachments. * `label` is an observability-only debug tag (see `_systemMessage`). */ export declare function _userMessage(msg: smoltalk.UserContentInput, label?: string, expires?: MessageExpiry): Promise; /** Seed a synthetic tool call and its result onto the active thread, as if * the model had made the call. Nothing executes: this only shapes the * conversation. `args` is validated by a JSON round-trip up front, so a * non-serializable value throws here rather than being rejected by the * provider on the next `llm()`. Both messages carry `label`, an * observability-only tag (see `_userMessage`). The id is synthetic — real * tool-call ids come from the provider, this one is minted with nanoid. */ export declare function _toolMessage(name: string, args: any, result: string, label?: string): Promise; export declare function __internal_assistantMessage(_ctx: RuntimeContext, _stack: StateStack, threads: ThreadStore, msg: string): Promise; /** ALS-reading replacement for `__internal_assistantMessage`. `label` is * an observability-only debug tag (see `_systemMessage`). */ export declare function _assistantMessage(msg: string, label?: string): Promise; export type AttachmentSource = { kind: "path"; path: string; mimeType?: string; } | { kind: "url"; url: string; mimeType?: string; } | { kind: "base64"; base64: string; mimeType: string; }; export type ImageAttachment = { type: "image"; source: AttachmentSource; }; export type FileAttachment = { type: "file"; source: AttachmentSource; filename?: string; }; export type AudioAttachment = { type: "audio"; source: AttachmentSource; filename?: string; }; export declare function classifySource(source: string, mimeType: string, base64: boolean): AttachmentSource; export declare function _imageAttachment(source: string, mimeType: string, base64: boolean): ImageAttachment; export declare function _fileAttachment(source: string, filename: string, mimeType: string, base64: boolean): FileAttachment; export declare function _audioAttachment(source: string, filename: string, mimeType: string, base64: boolean): AudioAttachment; /** Backs `std::thread.attachToReply`. Queues an attachment on the CALLING * TOOL INVOCATION's branch-local stack bag; the LLM tool loop harvests it * when the invocation completes and shows it to the model as a labeled * user message after the tool round (see lib/runtime/replyAttachments.ts). * Outside a tool invocation there is no tool loop to harvest, so the * attachment is dropped with a statelog error — never a throw (a tool * must not crash because its host context changed). * * A path source is read here, through the host, and queued as base64, * so the queue holds the bytes the tool meant and no later step reads * the disk. A path that is missing or over the size limit is queued * with the reason, which harvest puts in the skip marker. */ export declare function _attachToReply(attachment: unknown): Promise; /** Backs `std::thread.endTurn`. Marks the current tool invocation so the * tool loop ends the caller's llm() call when the tool returns. Same * contract as _attachToReply: outside a tool invocation there is no * tool loop to read the mark, so it is dropped with a statelog error, * never a throw. See docs/dev/language/handoff-functions.md. */ export declare function _endTurn(scope: TurnScope): void; /** Backs `std::thread.handBack`. Records the message a handoff hands * control back with. Same contract as _endTurn. */ export declare function _handBack(message: string): void; /** True while a tool invocation is on the stack. attachToReply is a * no-op outside one, and viewFile must not report success there. */ export declare function _insideToolCall(): boolean; /** Backs `std::thread.viewFile`. Runs before the interrupt, so it may * only look at the name and the stat, never the bytes. `realPath` was * already resolved through the host's files by the wrapper. */ export declare function _viewFilePrecheck(realPath: string): Promise<{ kind: "image" | "pdf"; }>; export declare function __internal_getCost(_ctx: RuntimeContext, stack: StateStack, _threads: ThreadStore): Promise; /** ALS-reading replacement for `__internal_getCost`. */ export declare function _getCost(): Promise; export declare function __internal_getTokens(_ctx: RuntimeContext, stack: StateStack, _threads: ThreadStore): Promise; /** ALS-reading replacement for `__internal_getTokens`. */ export declare function _getTokens(): Promise; /** True when the active message thread has no messages yet. Stdlib agents * use this to send their system prompt exactly once per thread: a fresh * thread has no messages, while a resumed session already carries its * prompt. */ export declare function _threadIsNew(): Promise; /** True when the active thread already holds a system message with * exactly this content. Reads the messages in place; nothing is copied. */ export declare function _threadHasSystemMessage(content: string): Promise; export type ReplyUsage = { inputTokens: number; outputTokens: number; }; /** One generated token and the log of its probability, as `lastReply()` * hands it back. `top` holds the likeliest alternatives at that position, * or an empty array when the call did not ask for them. */ export type ReplyTokenLogprob = { token: string; logprob: number; top: TokenAlternative[]; }; /** What the last assistant message on the active thread carried beyond its * text. `answers` is a decision model's answer per question, null for any * other reply. `rawData` is whatever the provider attached, untouched. * Null fields mean the reply carried nothing of that kind. */ export type ReplyRecord = { content: string; thinkingBlocks: ThinkingBlock[]; logprobs: ReplyTokenLogprob[]; usage: ReplyUsage | null; cost: number | null; answers: Record | null; rawData: unknown; }; /** The active thread's last assistant message as a `ReplyRecord`, or null * when no assistant has replied on it yet. Reads the messages in place, so * after a resume it sees what the checkpoint restored. */ export declare function _lastReply(): Promise; export type ModelCost = ModelUsage & { kind: UsageKind; }; /** * What the run has spent since it began, one row per kind and model, from the * same meter the run result's `usage.entries` comes from. It covers every * branch, subagent and tool, and a resumed run's earlier spend. Sorted by cost * descending, model name as the tiebreak. */ export declare function _getModelCosts(): Promise; export declare function __internal_pushGuard(ctx: RuntimeContext, stack: StateStack, _threads: ThreadStore, costLimit: number | null, timeLimit: number | null): Promise; /** ALS-reading replacement for `__internal_pushGuard`. */ export declare function _pushGuard(costLimit: number | null, timeLimit: number | null, label?: string | null): Promise; export declare function __internal_popGuard(_ctx: RuntimeContext, stack: StateStack, _threads: ThreadStore, ids: string[]): Promise; /** ALS-reading replacement for `__internal_popGuard`. */ export declare function _popGuard(ids: string[]): Promise; /** Impl of the Agency `saveDraft(value)` builtin. All the real logic — * which frame owns the draft, cloning, the global-scope rejection — * lives in `StateStack.setSavedDraft`. */ export declare function _saveDraft(value: unknown): Promise; /** * Run the guarded block under a `try` that owns exactly the guards in `ids`, * so a `guardTrip` is converted to a Failure ONLY when it belongs to one of * THIS guard()'s guards (an outer guard's trip re-throws past it). * * WHY THIS IS TS AND NOT AGENCY: the routing is `__tryCall(..., { * ownedGuardIds })`, and the agency `try block()` expression has no syntax to * pass `ownedGuardIds` into its `__tryCall` (it lowers to a fixed * `{ checkpoint, functionName, args }` — see processTryExpression in * lib/backends/typescriptBuilder.ts). Stashing the owned ids on the stack * frame for `__tryCall` to read globally is NOT an option either: a plain * `try` nested inside the guarded block must own NOTHING (so it re-throws the * guard's trip rather than swallowing it — see the fixture * guard-trip-not-swallowed-by-inner-try), so the owned set has to be scoped to * THIS specific `try` boundary, not read from the frame. Hence this small TS * seam. (The alternative is to extend the `try` codegen to carry * owned-guard-ids — a larger codegen change.) * * Because this replaces the stdlib `guard`'s former agency-level `try block()`, * it MUST forward the same FailureOpts that `try` injected ({ checkpoint, * functionName, args }) so a guard failure keeps its checkpoint / functionName * / args (retry + reporting depend on them) — only `ownedGuardIds` is added. */ export declare function _runGuarded(ids: string[], block: unknown): Promise;