mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 00:05:49 +02:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Legacy adapters can use host credentials and provider settings. > - OpenRouter assigns app credit from the final request headers. > - The first attribution change covered managed connections and explicit provider configs. > - Legacy Pi with only an API key bypassed those config changes. > - This pull request applies attribution at Pi's request boundary. > - The benefit is Paperclip credit without replacing the user's Pi home. ## Linked Issues or Issue Description Follow-up to #16850. A search of related OpenRouter PRs and issues found no duplicate fix for this path. **What happened?** A legacy `pi_local` agent with `OPENROUTER_API_KEY` and no `PAPERCLIP_PI_PROVIDERS` could send requests without Paperclip attribution. Existing Pi home configs could also retain the previous harness title. **Expected behavior** Paperclip receives credit for OpenRouter requests from its legacy Pi adapter. The adapter preserves credentials, routing, model settings, and other providers. **Steps to reproduce** 1. Configure a legacy Pi agent with an OpenRouter model and API key. 2. Leave `PAPERCLIP_PI_PROVIDERS` unset. 3. Start a run and inspect its outgoing headers or OpenRouter generation record. **Paperclip version or commit** Reproduced after #16850, on master commit `9179d8dcc3e908c217fde4f63c9d08ccf8132eeb`. ## What Changed - Load a temporary attribution extension for every legacy Pi run, including remote targets and retries. - Apply headers after credential and model-header resolution on Pi 0.74 and at provider dispatch on Pi 1.0. - Check the actual endpoint. Cover custom aliases and regional OpenRouter hosts. Preserve other endpoints, credentials, unrelated headers, and explicit visibility preferences. - Keep the Pi home, auth file, settings, and model catalog in place. Remove the temporary extension after the run. - Prevent repeated wrapping when Pi recomposes a provider after a registry refresh. Add regression tests and update the connector playbook. ## Verification - Final head `902399468a9033d12e3ff6ab30c8463daef50bad`: Greptile **5/5**, with no actionable comments. CI is waiting for runner assignment. - Complete legacy Pi adapter suite: **124 tests passed across 12 files**, including extension, runtime-config, and remote execution coverage. The initial focused subset passed 30 tests. - `pnpm -r typecheck` and `pnpm build` passed. After the lifecycle guard, all 124 Pi tests and the Pi package typecheck passed again. Full `pnpm test:run` is in progress. - Actual Pi 0.74 outgoing-request comparison with dummy credentials: the baseline sent no attribution headers. The patched request sent all four Paperclip headers and retained the same credential. The transport returned an intentional 401 after capture; this check does not claim successful inference. - Final-head Pi 0.74 request-capture matrix: **8/8 passed**. Cases cover bare keys, host aliases, per-model overrides, EU/US endpoints, a repointed built-in provider, an unrelated provider, and an HTTP endpoint. Credentials, custom routing headers, and visibility preferences survived. These captures used dummy credentials and intentional 401 responses. - Live request through the actual legacy adapter with Pi 0.74: response `legacy attribution verified.`; generation `gen-1792424885-G3THa6DdJXmAL3C841DI`; OpenRouter app ID **3118063**; cost **$0.0002268**. - Live request through the actual legacy adapter with the Pi 1.0 bundled CLI: response `legacy attribution verified.`; generation `gen-1792425530-LlpIbfBFyjs6XRP5l5PV` on final head `902399468a9033d12e3ff6ab30c8463daef50bad`; OpenRouter app ID **3118063**; cost **$0.0002391**. Its usage record became available on a later read. - Both live runs preserved the existing `models.json`, `settings.json`, and `auth.json` byte for byte. Pi 0.74 also retained the custom `X-Route` header while replacing the conflicting harness title. - Built-package smoke passed. `npm pack --dry-run --ignore-scripts` includes `dist/server/openrouter-extension.js`, and the compiled helper produced a working self-contained extension. The pack check used a temporary npm cache because the default cache was not writable. - Remote asset delivery is covered through the SSH execution test boundary. No live remote sandbox was used. - Initial capture attempts produced no requests because the test left stdin open. A separate source-checkout live attempt lacked the TypeScript loader and did not reach the provider. Correcting the test setup produced the evidence above. Pi 1.0's bundled transport bypassed the global-fetch capture shim; its acceptance evidence is the successful live request and provider-side app ID. ## Risks - The extension depends on Pi 0.74's request-auth registry and Pi 1.0's provider API. Harness upgrades require a fresh request capture or live credit check. - Missing extension delivery stops remote startup rather than silently losing attribution. - A private gateway that replaces headers and an externally managed harness remain outside this adapter's control. Public listing metadata still belongs to OpenRouter. - No database, API, credential ownership, or telemetry contract changes are required. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository editing, shell execution, and live API verification. The exact runtime model identifier and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass — the focused suites above; the full suite is still running - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>