Skip to content

feat: add token counting (OpenAI tiktoken + Claude API) #20

Description

@kiki830621

Summary

Add macdoc convert --to tokens <file> that outputs exact token counts.

Depends on #27 (CLI migration to convert --to pattern).

CLI Interface

macdoc convert --to tokens file.md                        # both models
macdoc convert --to tokens --model gpt-4o file.md         # OpenAI only
macdoc convert --to tokens --model claude-sonnet file.md   # Claude only

Output Format

# Default (tabular)
Model              Tokens
─────────────────────────
gpt-4o             1,234
claude-sonnet-4-6  1,198

# Single model (just the number for piping)
1234

Token Counting Methods

Provider Method Cost
OpenAI swift-tiktoken (offline BPE) Free, offline
Claude Anthropic /v1/messages/count_tokens API Free, online (RPM-limited)

Architecture

  • New package: token-counter-swift under packages/
  • Layer 2 utility (measurement tool, not format converter)
  • Depends on: swift-tiktoken, Foundation (URLSession for Anthropic API)
  • Needs ANTHROPIC_API_KEY env var for Claude counting

References

Phase: closed
Last updated: 2026-09-01 by idd-close

Key Decisions

  • Public models are exactly gpt-4o and claude-sonnet-4-6; default order is GPT then Claude, with all-or-nothing TSV presentation.
  • GPT-4o uses a pinned pure-Swift BPE and SHA-256-verified bundled o200k_base; runtime network/download/cache/HOME writes are prohibited.
  • Every Claude request requires per-invocation --allow-network plus a non-empty ANTHROPIC_API_KEY after local preflight.
  • Production URLSession uses a data delegate and retains at most 65,537 package-owned response bytes; Foundation callback allocation is explicitly outside the enforceable boundary.
  • Public injected transport bytes/errors are independently bounded and redacted; cancellation and redirect keep typed outcomes through presentation.
  • Input admission uses one no-follow descriptor for fstat and capped UTF-8 read; maximum size is 1,000,000 bytes.

Scope Changes

  • Round 3 replaced the impossible network-buffering claim with the enforceable package-retention contract; this is a precision correction, not a privacy relaxation.
  • Added explicit service/CLI cancellation semantics and production redirect coverage.
  • Live Anthropic validation, additional models, cost prediction, stdin, streaming input, and configurable endpoints remain out of scope.

Blocking

Tasks

  • Add reusable TokenCounter package and exact tokenizer dependency pin.
  • Bundle and integrity-check offline o200k_base; pass official reference vectors.
  • Implement fixed Anthropic request, consent/key preflight, typed errors, no retry, and redaction.
  • Enforce delegate callback retention, injected response/error bounds, cancellation, and redirect semantics.
  • Add descriptor-safe 1,000,000-byte UTF-8 input admission.
  • Add deterministic single/dual output and atomic failure/cancellation presentation.
  • Add compiled CLI, package, provider-stub, privacy, resource, and documentation acceptance.
  • Pass 30 package tests, 22 token CLI tests, full root suite, Spectra strict, manifests, digest, and diff checks.
  • Complete five independent reviewer lenses with all blocking findings corrected and re-reviewed to PASS.

Commits

Pull Request

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions