@yul-labs/agent-relay 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -128,7 +128,9 @@ interface ApiDeciderOptions {
128
128
  * Default 2048. Reasoning models emit a long chain-of-thought before the JSON
129
129
  * answer, so a too-small cap (e.g. a few hundred) truncates them mid-thought,
130
130
  * leaving an empty `content` and an unparseable reply → safe-deny. Raise it
131
- * (not lower) for verbose reasoning models.
131
+ * (not lower) for verbose reasoning models. Values below
132
+ * {@link MIN_API_MAX_TOKENS} are clamped UP to it — a cap that small can't fit
133
+ * even the JSON answer once a reasoning model has spent budget on its CoT.
132
134
  */
133
135
  maxTokens?: number;
134
136
  temperature?: number;
@@ -259,6 +261,43 @@ interface AgentRunInput {
259
261
  /** Arbitrary extra options interpreted by specific adapters (e.g. fake). */
260
262
  options?: Record<string, unknown>;
261
263
  }
264
+ /**
265
+ * Resource usage for a run, exposed under `result.meta.usage`. Every field is
266
+ * optional. Token counts come from the agent's own session transcript/rollout
267
+ * JSONL (the AUTHORITATIVE, device-independent source — written on every run
268
+ * regardless of TUI/status-line settings); `contextPercent` / `sessionCostUsd`
269
+ * are best-effort extras scraped from the TUI status line when it is enabled.
270
+ * `source` records which path produced the token figures.
271
+ */
272
+ interface AgentUsage {
273
+ /**
274
+ * Provenance of the token counts: "transcript" = parsed from the agent's
275
+ * session log (authoritative); "status-line" = scraped from the TUI (only
276
+ * present when the user has a status line that shows usage). Token fields are
277
+ * trustworthy only when `source` is "transcript".
278
+ */
279
+ source?: "transcript" | "status-line";
280
+ /** Model id when known, e.g. "claude-opus-4-8". */
281
+ model?: string;
282
+ /** Cumulative non-cached input/prompt tokens. */
283
+ inputTokens?: number;
284
+ /** Cumulative output/completion tokens. */
285
+ outputTokens?: number;
286
+ /** Cumulative tokens served from the prompt cache (cheap reads). */
287
+ cachedInputTokens?: number;
288
+ /** Cumulative tokens spent CREATING prompt-cache entries (Claude). */
289
+ cacheCreationTokens?: number;
290
+ /** Cumulative reasoning tokens, when the model reports them (Codex / o-series). */
291
+ reasoningTokens?: number;
292
+ /** Total tokens (the agent's own total when given, else the sum of the above). */
293
+ totalTokens?: number;
294
+ /** Context-window usage as a percent, when surfaced by the status line. */
295
+ contextPercent?: number;
296
+ /** Session cost (USD) when the agent reports it; reads 0 on subscription billing. */
297
+ sessionCostUsd?: number;
298
+ /** Raw status-line snippet the scraped extras came from (status-line only). */
299
+ raw?: string;
300
+ }
262
301
  /** The terminal result an adapter returns from {@link AgentAdapter.run}. */
263
302
  interface AgentRunResult {
264
303
  /** Whether the adapter believes the run finished successfully. */
@@ -1289,6 +1328,13 @@ interface PtySessionOptions {
1289
1328
  * think/build is never mistaken for "done".
1290
1329
  */
1291
1330
  workingPattern?: RegExp;
1331
+ /**
1332
+ * Optional per-adapter scrape of the (ANSI-cleaned) screen into structured
1333
+ * usage (tokens / context / cost). Called on each settle; the latest non-empty
1334
+ * result is merged and attached to `result.meta.usage`. Vendor-specific, so the
1335
+ * adapter supplies it — the session loop itself stays vendor-agnostic.
1336
+ */
1337
+ scrapeUsage?: (cleanedText: string) => AgentUsage | undefined;
1292
1338
  /** Keys to send to exit the TUI on completion (e.g. double Ctrl-C). */
1293
1339
  quitKeys?: string;
1294
1340
  /** Optional text to type once the UI is ready (for TUIs needing typed input). */
@@ -1355,6 +1401,13 @@ interface InteractiveAdapterConfig {
1355
1401
  setup?: (input: AgentRunInput) => SetupStep[] | undefined;
1356
1402
  detector?: PromptDetectorOptions;
1357
1403
  keymap?: PtyKeymap;
1404
+ /**
1405
+ * Optional per-adapter scrape of the agent's TUI status line into structured
1406
+ * usage (tokens / context / cost), surfaced as `result.meta.usage`. Heuristic
1407
+ * and vendor-specific, so it lives in the adapter, not the vendor-agnostic
1408
+ * session loop. Omit it for adapters with no parseable status line.
1409
+ */
1410
+ scrapeUsage?: (cleanedText: string) => AgentUsage | undefined;
1358
1411
  completionPattern?: RegExp;
1359
1412
  completionIdleMs?: number;
1360
1413
  /** "Agent is working" indicator that suppresses completion (see PtySession). */
@@ -1387,18 +1440,34 @@ declare class InteractivePtyAdapter implements AgentAdapter {
1387
1440
  * AUTONOMY: by default Claude runs with `--dangerously-skip-permissions` so it
1388
1441
  * acts without per-action prompts. The {@link Decider} still handles the prompts
1389
1442
  * that appear anyway (the directory-trust menu, etc.). `approvalPolicy: "gated"`
1390
- * uses `--permission-mode acceptEdits` so Claude asks more and the decider sees
1391
- * those; `"readonly"` uses `--permission-mode plan`. The prompt is a positional
1392
- * arg so the session starts immediately.
1443
+ * uses `--permission-mode default` Claude's normal interactive mode where it
1444
+ * ASKS before each edit/command, so those approvals are routed to the decider.
1445
+ * (NOT `acceptEdits`, which silently auto-approves edits and so never consults
1446
+ * the decider on them.) `"readonly"` uses `--permission-mode plan`. The prompt is
1447
+ * a positional arg so the session starts immediately.
1393
1448
  */
1394
1449
 
1395
1450
  interface ClaudeInteractiveOptions {
1396
1451
  command?: string;
1397
1452
  env?: Record<string, string>;
1398
1453
  now?: () => Date;
1454
+ /** Override Claude's projects root (~/.claude/projects) — for tests. */
1455
+ projectsDir?: string;
1399
1456
  }
1400
1457
  declare class ClaudeInteractiveAdapter extends InteractivePtyAdapter {
1458
+ private readonly clock;
1459
+ /** Override the projects root (~/.claude/projects) for tests. */
1460
+ private readonly projectsDir?;
1401
1461
  constructor(opts?: ClaudeInteractiveOptions);
1462
+ /**
1463
+ * Run Claude, then read AUTHORITATIVE token usage from its session transcript
1464
+ * (~/.claude/projects/<cwd>/<id>.jsonl) and surface it as `meta.usage`. This is
1465
+ * device-independent — it works regardless of whether the user has a usage
1466
+ * status line — and overwrites the best-effort status-line scrape's token
1467
+ * figures while keeping its context%/cost extras. Best-effort: if no transcript
1468
+ * is found, the status-line usage (if any) is left as-is.
1469
+ */
1470
+ run(input: AgentRunInput, ctx: AdapterRunContext): Promise<AgentRunResult>;
1402
1471
  static fromConfig(config: AdapterConfig): ClaudeInteractiveAdapter;
1403
1472
  }
1404
1473
 
@@ -1424,11 +1493,12 @@ declare class CodexInteractiveAdapter extends InteractivePtyAdapter {
1424
1493
  private readonly sessionsDir?;
1425
1494
  constructor(opts?: CodexInteractiveOptions);
1426
1495
  /**
1427
- * Run Codex, then capture its NATIVE session id (the rollout UUID) for this
1428
- * cwd and attach it to the result's `sessionRef` so the runner persists it and
1429
- * a later resume can use `codex resume <id> "<prompt>"`. Capture is best-effort:
1430
- * if no rollout matches (or any I/O fails) the result is returned unchanged, so
1431
- * the run still resumes via the `--last` fallback.
1496
+ * Run Codex, then read its rollout for this cwd to capture (a) the NATIVE
1497
+ * session id (the rollout UUID) for `sessionRef` so a later resume can use
1498
+ * `codex resume <id> "<prompt>"`, and (b) authoritative token usage for
1499
+ * `meta.usage` (device-independent from Codex's own log, not the TUI). Both
1500
+ * are best-effort: if no rollout matches (or any I/O fails) the result is
1501
+ * returned unchanged, so the run still resumes via the `--last` fallback.
1432
1502
  */
1433
1503
  run(input: AgentRunInput, ctx: AdapterRunContext): Promise<AgentRunResult>;
1434
1504
  static fromConfig(config: AdapterConfig): CodexInteractiveAdapter;
@@ -1695,4 +1765,4 @@ declare function cleanTerminalText(input: string): string;
1695
1765
  /** Return the last `n` non-empty lines of cleaned text. */
1696
1766
  declare function tailLines(text: string, n: number): string[];
1697
1767
 
1698
- export { type AbortReason, type AdapterAvailability, type AdapterConfig, type AdapterFactory, type AdapterListItem, type AdapterMode, AdapterRegistry, type AdapterRunContext, type AgentAdapter, type AgentAdapterDefinition, type AgentErrorInfo, type AgentEvent, type AgentEventType, AgentRelayError, type AgentRunInput, type AgentRunResult, type AgentSessionRef, AlwaysApproveDecider, ApiDecider, type ApprovalMode, BUILTIN_ADAPTER_DEFINITIONS, CONFIG_FILENAME, ClaudeInteractiveAdapter, CodexInteractiveAdapter, CommandDecider, type CommandPreview, type CompletionContext, type CompletionDetector, CompositeCompletionDetector, ConfigError, type CreateSessionInput, DEFAULT_DENY_PATTERNS, type Decider, type DeciderConfig, type DeciderConfigSchema, type DeciderFlags, type DecisionAction, DefaultCompletionDetector, DefaultKeymap, type DetectedPrompt, type DoctorReport, type FakeAdapterOptions, FakeAgentAdapter, FunctionDecider, type HooksConfig, type InitResult, type InteractionDecision, type InteractionKind, type InteractionRequest, type InteractiveAdapterConfig, InteractivePtyAdapter, OutputPatternDetector, PromptDetector, type PromptDetectorOptions, type PruneOptions, type PruneResult, type PtyKeymap, type PtySessionOptions, type RelayConfig, type RelayDefaults, type ResumeCommandResult, RuleDecider, type RunHooks, RunLogger, type RunLoggerOptions, type RunOutcome, type RunnerOptions, type SandboxLevel, type SessionListItem, SessionManager, type SessionMetadata, SessionNotFoundError, type SessionStatus, type ShellHookContext, type ShellHooks, UnknownAdapterError, adapterConfigSchema, approvalPolicySchema, cleanTerminalText, configPath, configSchema, createAdapterFactory, createDecider, createDefaultConfig, deciderConfigFromFlags, deciderSchema, defaultRegistry, defaultsSchema, hooksSchema, listAdapters, listSessions, loadConfig, loadConfigOrDefault, parseCheckbox, parseConfig, parseDecisionReply, pruneSessions, renderDecisionPrompt, resolveApprovalMode, resolvePrompt, resolveSandbox, resumeCommand, runAgent, runCommand, runDoctor, runInit, runPtySession, runShellHook, sandboxSchema, saveConfig, stringifyConfig, stripAnsi, tailLines };
1768
+ export { type AbortReason, type AdapterAvailability, type AdapterConfig, type AdapterFactory, type AdapterListItem, type AdapterMode, AdapterRegistry, type AdapterRunContext, type AgentAdapter, type AgentAdapterDefinition, type AgentErrorInfo, type AgentEvent, type AgentEventType, AgentRelayError, type AgentRunInput, type AgentRunResult, type AgentSessionRef, type AgentUsage, AlwaysApproveDecider, ApiDecider, type ApprovalMode, BUILTIN_ADAPTER_DEFINITIONS, CONFIG_FILENAME, ClaudeInteractiveAdapter, CodexInteractiveAdapter, CommandDecider, type CommandPreview, type CompletionContext, type CompletionDetector, CompositeCompletionDetector, ConfigError, type CreateSessionInput, DEFAULT_DENY_PATTERNS, type Decider, type DeciderConfig, type DeciderConfigSchema, type DeciderFlags, type DecisionAction, DefaultCompletionDetector, DefaultKeymap, type DetectedPrompt, type DoctorReport, type FakeAdapterOptions, FakeAgentAdapter, FunctionDecider, type HooksConfig, type InitResult, type InteractionDecision, type InteractionKind, type InteractionRequest, type InteractiveAdapterConfig, InteractivePtyAdapter, OutputPatternDetector, PromptDetector, type PromptDetectorOptions, type PruneOptions, type PruneResult, type PtyKeymap, type PtySessionOptions, type RelayConfig, type RelayDefaults, type ResumeCommandResult, RuleDecider, type RunHooks, RunLogger, type RunLoggerOptions, type RunOutcome, type RunnerOptions, type SandboxLevel, type SessionListItem, SessionManager, type SessionMetadata, SessionNotFoundError, type SessionStatus, type ShellHookContext, type ShellHooks, UnknownAdapterError, adapterConfigSchema, approvalPolicySchema, cleanTerminalText, configPath, configSchema, createAdapterFactory, createDecider, createDefaultConfig, deciderConfigFromFlags, deciderSchema, defaultRegistry, defaultsSchema, hooksSchema, listAdapters, listSessions, loadConfig, loadConfigOrDefault, parseCheckbox, parseConfig, parseDecisionReply, pruneSessions, renderDecisionPrompt, resolveApprovalMode, resolvePrompt, resolveSandbox, resumeCommand, runAgent, runCommand, runDoctor, runInit, runPtySession, runShellHook, sandboxSchema, saveConfig, stringifyConfig, stripAnsi, tailLines };