← All @molecule/* packages · App templates

@molecule/api-text-provenance

Core interface · text-provenance · API (Node) · v1.0.0 · Apache-2.0

Attributes a document's paragraphs to the agent sessions that wrote them: human or AI, the prompt and model behind each, and the AI word share

npm install @molecule/api-text-provenance

npm · Source on GitHub

How it works

@molecule/api-text-provenance is the text-provenance core interface on the API (Node) side: the API your app calls, with no vendor inside.

Choose the implementation by bonding one of its 1 provider: @molecule/api-text-provenance-overlap.

import { readFileSync } from 'node:fs'
import { readTranscript, setProvider as setReader } from '@molecule/api-agent-transcript'
import { provider as reader } from '@molecule/api-agent-transcript-autodetect'
import { attributeText, setProvider } from '@molecule/api-text-provenance'
import { provider as overlap } from '@molecule/api-text-provenance-overlap'

setReader(reader)
setProvider(overlap)

const session = readTranscript({ text: readFileSync('transcripts/post/codex-session.md', 'utf8') })
const paragraphs = ['A paragraph the person wrote.', 'A paragraph the agent drafted …']
const result = attributeText({ paragraphs, sessions: [session] })
// result.paragraphs[1] → { origin: 'ai', prompt: 'Write the section about …', model: 'gpt-…', … }
// result.aiShare → 0.62, result.prompts → ['Write the section about …']

Providers (1): @molecule/api-text-provenance-overlap

Works with: @molecule/api-agent-transcript, @molecule/api-bond, @molecule/api-i18n

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Which paragraphs of a document an AI wrote — and the prompt and model behind each.

Give it the document's paragraphs and the coding-agent sessions that produced it (read with @molecule/api-agent-transcript); it returns each paragraph as human or ai, the user message each AI paragraph answered (as typed) and the model that wrote it, plus the document's AI word share and the distinct prompts. Use it for "written with AI" disclosures, a margin mark on AI paragraphs, a prompt shown beside the prose, or an audit of generated docs. @molecule/api-text-provenance-overlap is the provider.

Quick Start

import { readFileSync } from 'node:fs'
import { readTranscript, setProvider as setReader } from '@molecule/api-agent-transcript'
import { provider as reader } from '@molecule/api-agent-transcript-autodetect'
import { attributeText, setProvider } from '@molecule/api-text-provenance'
import { provider as overlap } from '@molecule/api-text-provenance-overlap'

setReader(reader)
setProvider(overlap)

const session = readTranscript({ text: readFileSync('transcripts/post/codex-session.md', 'utf8') })
const paragraphs = ['A paragraph the person wrote.', 'A paragraph the agent drafted …']
const result = attributeText({ paragraphs, sessions: [session] })
// result.paragraphs[1] → { origin: 'ai', prompt: 'Write the section about …', model: 'gpt-…', … }
// result.aiShare → 0.62, result.prompts → ['Write the section about …']

Type

core

Installation

npm install @molecule/api-text-provenance @molecule/api-agent-transcript @molecule/api-bond @molecule/api-i18n

API

Interfaces

Attribution

A document's attribution.

interface Attribution {
  /** One entry per input paragraph, in order. */
  paragraphs: ParagraphAttribution[]
  /** Words in the whole document. */
  words: number
  /** Words in the paragraphs attributed to the AI. */
  aiWords: number
  /** `aiWords / words` (0 for an empty document). */
  aiShare: number
  /** The distinct prompts behind the AI paragraphs, in the order they first appear in the document. */
  prompts: string[]
}

AttributionInput

What to attribute: the document's paragraphs and the sessions that may have written them.

interface AttributionInput {
  /** The document's paragraphs as plain text, in order (headings and list items may be passed as their own blocks). */
  paragraphs: readonly string[]
  /** The agent sessions behind the document (`@molecule/api-agent-transcript`). None = all human. */
  sessions: readonly AgentSession[]
  /** Tuning. */
  options?: AttributionOptions
}

AttributionOptions

Tuning for an attribution.

interface AttributionOptions {
  /**
   * The share of a paragraph's words that must come from the AI for the
   * paragraph to count as AI-written. Default 0.5.
   */
  minAiShare?: number
}

ParagraphAttribution

One paragraph's attribution.

interface ParagraphAttribution {
  /** The paragraph's position in the input. */
  index: number
  /** `ai` when at least `minAiShare` of its words came from the AI and not from the user. */
  origin: ParagraphOrigin
  /** How many words it has. */
  words: number
  /** How many of them came from the AI (and were not typed by the user). */
  aiWords: number
  /** For an `ai` paragraph: the user message, as typed, that the writing answered. */
  prompt?: string
  /** For an `ai` paragraph: the model that wrote it, when the session records one. */
  model?: string
  /** For an `ai` paragraph: which session (index into `sessions`) and turn (index into its `turns`) wrote it. */
  source?: { session: number; turn: number }
}

TextProvenanceProvider

The contract every attribution bond implements.

interface TextProvenanceProvider {
  /**
   * Attribute each paragraph to the human or to the AI.
   *
   * @param input - The paragraphs, the sessions, and tuning.
   * @returns The attribution.
   */
  attribute(input: AttributionInput): Attribution
}

Types

ParagraphOrigin

Who wrote a paragraph.

type ParagraphOrigin = 'human' | 'ai'

Functions

attributeText(input)

Attribute a document's paragraphs to the human or to the AI with the bonded provider.

function attributeText(input: AttributionInput): Attribution
  • input — The paragraphs, the agent sessions behind them, and tuning.

Returns: Per paragraph: origin, prompt and model; for the document: word counts, AI share and prompts.

getProvider()

Retrieves the bonded attribution provider, throwing if none is configured.

function getProvider(): TextProvenanceProvider

Returns: The bonded provider.

hasProvider()

Checks whether an attribution provider is bonded.

function hasProvider(): boolean

Returns: true if a provider is bonded.

setProvider(provider)

Registers an attribution provider as the active one. Called during application startup.

function setProvider(provider: TextProvenanceProvider): void
  • provider — The provider to bond.

Available Providers

ProviderPackage
Text provenance by word overlap@molecule/api-text-provenance-overlap

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-agent-transcript ^1.0.0
  • @molecule/api-bond ^1.0.1
  • @molecule/api-i18n ^1.0.1

Runtime Dependencies

  • @molecule/api-agent-transcript

  • @molecule/api-bond

  • @molecule/api-i18n

  • The caller passes everything: the paragraphs (plain text — render markdown first, or pass the source's blocks) and the sessions. Nothing is read from disk or guessed; no sessions means every paragraph is human.

  • The user's own words are never the AI's. A paragraph the person typed into a prompt stays human even when the agent later wrote it into a file.

  • A light human edit of an AI paragraph stays AI; a rewrite that keeps less than minAiShare (default 0.5) of the AI's words becomes human.

  • Word counts are the attribution's own (letters and digits); the AI share is by words, per paragraph — a paragraph counts wholly one way.

  • Pure and synchronous. Run it at build time and publish the result (for example as a per-post provenance.json).