@skaile/transform-proxy 0.3.1 → 0.4.0
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/CHANGELOG.md +8 -0
- package/README.md +5 -1
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{config-BZsthgP-.mjs → config-Ceb5AF_a.mjs} +24 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/omp/index.mjs +1 -1
- package/dist/{server-C_eKyCTV.d.mts → server-CicvlQ7q.d.mts} +8 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
- Library: `TransformProxy.inspect(sessionId, pipelineId?)` returns host-only transform state, `{ <transformId>: state }` for each stage of the session's pipeline instance (default `defaultPipeline`) that implements the new optional `Transform.inspect?()`. A host such as anon-ai reads forge-anon's mapping through it to show what was anonymized. It is in-process only (no HTTP route, never sent), returns `{}` for an unknown session, an unbuilt pipeline or a failed build, and never builds an instance or creates session state.
|
|
6
|
+
|
|
7
|
+
## 0.3.1
|
|
8
|
+
|
|
9
|
+
- Anthropic walker: the system text that Anthropic's Claude subscription (OAuth) check reads verbatim passes untransformed: the leading Claude Code identity sentence and the leading `x-anthropic-billing-header:` line. The rest of each block is still transformed. forge-anon read `Claude` as a name and the `cc_version` as IP addresses, so every request of a subscription session with anon on got 429 `rate_limit_error` "Error".
|
|
10
|
+
|
|
3
11
|
## 0.3.0
|
|
4
12
|
|
|
5
13
|
- omp extension, **behaviour change**: `/anon on` and `/anon off` switch only the omp process they run in (its subagents and its `/new`, `/resume`, `/fork` sessions included) and no longer save the default. Before, every `/anon on|off` wrote `~/.omp/agent/skaile-transform-proxy.json`, so turning anon off in one window turned it off for every omp started later. `/anon on --global` and `/anon off --global` also save the default. A saved `on` is applied at session start only until the first successful `/anon on|off` in that process, so a plain `/anon off` stays off across `/new`. An existing saved `enabled: true` still turns anon on in new omp processes; run `/anon off --global` to clear it.
|
package/README.md
CHANGED
|
@@ -85,6 +85,8 @@ await proxy.dropSession('s1')
|
|
|
85
85
|
await proxy.close()
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
`await proxy.inspect('s1')` lets the host read what the session's transforms hold, e.g. forge-anon's mapping for highlights: `{ <transformId>: state }`, one entry per stage of the pipeline (`inspect('s1', 'anon')`; default `defaultPipeline`) whose `Transform` implements `inspect()`. It is in-process only: there is no HTTP route, and the result is never sent anywhere. An unknown session, a pipeline that has not been built for the session yet, or a failed build gives `{}`; `inspect` never builds an instance or creates session state.
|
|
89
|
+
|
|
88
90
|
## omp extension
|
|
89
91
|
|
|
90
92
|
The package ships an [omp](https://omp.sh) extension (subpath `@skaile/transform-proxy/omp`, declared in the package manifest under `omp.extensions`):
|
|
@@ -128,10 +130,12 @@ A module default-exports a `TransformModule`:
|
|
|
128
130
|
|
|
129
131
|
- `open(config, { baseDir, log })` runs once per proxy. It validates the config and builds shared state. Throwing rejects startup.
|
|
130
132
|
- It returns a `TransformFactory`, which runs once per `(session, pipeline)`: `(ctx: { sessionId, facts, log }) => Transform`.
|
|
131
|
-
- A `Transform` has `instruction?`, `outbound(text, leaf)`, `inbound(text)`, `inboundStream()` and `
|
|
133
|
+
- A `Transform` has `instruction?`, `outbound(text, leaf)`, `inbound(text)`, `inboundStream()`, `dispose?()` and `inspect?()` (host-only state, read through `proxy.inspect`; the walkers never call it).
|
|
132
134
|
|
|
133
135
|
The Anthropic walker appends the pipeline `instruction` after the host's system prompt: a string `system` gets it after a blank line, a block array gets it as one more text block at the end, and an absent `system` becomes the instruction. The host's leading blocks stay first, because Claude Code gateways (TeamClaude) refuse Sonnet requests with 429 `rate_limit_error` when the system prompt does not start with the Claude Code blocks. The OpenAI walkers still put the instruction first: a leading `system` message in chat completions, a prefix of `instructions` in responses.
|
|
134
136
|
|
|
137
|
+
Those leading blocks also pass untransformed: a system text that starts with the Claude Code identity sentence (`You are Claude Code, Anthropic's official CLI for Claude.`) keeps that sentence, and one that starts with `x-anthropic-billing-header:` keeps that first line; the rest of the text is transformed. Anthropic's Claude subscription (OAuth) check reads them verbatim and answers 429 `rate_limit_error` with the message `Error` when they differ, and a German NER reads `Claude` as a name and a `cc_version` as an IP address. The host writes these blocks; they carry no user data.
|
|
138
|
+
|
|
135
139
|
`inboundStream().push(c1) + … + flush()` must equal `inbound(c1 + … + cn)` for every chunking.
|
|
136
140
|
|
|
137
141
|
Connectors publish facts through `proxy.session(id).publisher(source)`. Facts are in-process only.
|
package/dist/cli.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as TransformProxy } from "./server-
|
|
1
|
+
import { i as TransformProxy } from "./server-CicvlQ7q.mjs";
|
|
2
2
|
/** Environment variable that supplies the client token when `--token` is absent. */
|
|
3
3
|
export declare const TOKEN_ENV = "SKAILE_TRANSFORM_PROXY_TOKEN";
|
|
4
4
|
export interface CliEnvironment {
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { d as createTransformProxy, o as resolveProxyConfig, v as errorMessage } from "./config-
|
|
2
|
+
import { d as createTransformProxy, o as resolveProxyConfig, v as errorMessage } from "./config-Ceb5AF_a.mjs";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { homedir } from "node:os";
|
|
@@ -1424,6 +1424,8 @@ async function createTransformProxy(options) {
|
|
|
1424
1424
|
const factories = await openTransforms(options.transforms, options.baseDir, log);
|
|
1425
1425
|
const pipelines = options.pipelines;
|
|
1426
1426
|
const sessions = /* @__PURE__ */ new Map();
|
|
1427
|
+
/** Composed instance -> its stages with their transform ids, for `inspect`. */
|
|
1428
|
+
const stagesOf = /* @__PURE__ */ new WeakMap();
|
|
1427
1429
|
function stateFor(id) {
|
|
1428
1430
|
const existing = sessions.get(id);
|
|
1429
1431
|
if (existing) return existing;
|
|
@@ -1456,7 +1458,12 @@ async function createTransformProxy(options) {
|
|
|
1456
1458
|
}
|
|
1457
1459
|
throw err;
|
|
1458
1460
|
}
|
|
1459
|
-
|
|
1461
|
+
const composed = composeTransforms(stages, log);
|
|
1462
|
+
stagesOf.set(composed, ids.map((id, i) => ({
|
|
1463
|
+
id,
|
|
1464
|
+
transform: stages[i]
|
|
1465
|
+
})));
|
|
1466
|
+
return composed;
|
|
1460
1467
|
}
|
|
1461
1468
|
async function handle(req, res) {
|
|
1462
1469
|
const url = new URL(req.url ?? "/", "http://proxy.invalid");
|
|
@@ -1573,6 +1580,22 @@ async function createTransformProxy(options) {
|
|
|
1573
1580
|
sessions.delete(id);
|
|
1574
1581
|
await disposeInstances(state, log);
|
|
1575
1582
|
},
|
|
1583
|
+
async inspect(sessionId, pipelineId) {
|
|
1584
|
+
const state = sessions.get(sessionId);
|
|
1585
|
+
const pipeline = pipelineId ?? options.defaultPipeline;
|
|
1586
|
+
if (state === void 0 || pipeline === void 0) return {};
|
|
1587
|
+
const pending = state.instances.get(pipeline);
|
|
1588
|
+
if (pending === void 0) return {};
|
|
1589
|
+
let instance;
|
|
1590
|
+
try {
|
|
1591
|
+
instance = await pending;
|
|
1592
|
+
} catch {
|
|
1593
|
+
return {};
|
|
1594
|
+
}
|
|
1595
|
+
const result = {};
|
|
1596
|
+
for (const stage of stagesOf.get(instance) ?? []) if (typeof stage.transform.inspect === "function") result[stage.id] = stage.transform.inspect();
|
|
1597
|
+
return result;
|
|
1598
|
+
},
|
|
1576
1599
|
async close() {
|
|
1577
1600
|
const closed = Promise.withResolvers();
|
|
1578
1601
|
server.close((err) => err ? closed.reject(err) : closed.resolve());
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as TransformModule, a as TransformProxyOptions, c as TransformSpec, d as SessionFactPublisher, f as SessionFacts, g as TransformFactory, h as Transform, i as TransformProxy, l as Logger, m as TextLeafKind, n as SESSION_HEADER, o as UPSTREAM_HEADER, p as TextLeaf, r as TOKEN_HEADER, s as createTransformProxy, t as PIPELINE_HEADER, u as SessionFact, v as TransformSessionContext } from "./server-
|
|
1
|
+
import { _ as TransformModule, a as TransformProxyOptions, c as TransformSpec, d as SessionFactPublisher, f as SessionFacts, g as TransformFactory, h as Transform, i as TransformProxy, l as Logger, m as TextLeafKind, n as SESSION_HEADER, o as UPSTREAM_HEADER, p as TextLeaf, r as TOKEN_HEADER, s as createTransformProxy, t as PIPELINE_HEADER, u as SessionFact, v as TransformSessionContext } from "./server-CicvlQ7q.mjs";
|
|
2
2
|
/** One stage's streamed inbound transformer, as returned by `Transform.inboundStream()`. */
|
|
3
3
|
interface InboundStream {
|
|
4
4
|
push(chunk: string): string;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as CONFIG_FILE_NAME, s as PIPELINE_HEADER, c as SESSION_HEADER, l as TOKEN_HEADER, u as UPSTREAM_HEADER, h as UnsupportedContentError, m as anthropicWalker, _ as composeTransforms, n as configCandidates, g as createSessionFacts, d as createTransformProxy, r as findProxyConfig, i as loadProxyConfig, p as openaiChatWalker, f as openaiResponsesWalker, a as parseProxyConfig, o as resolveProxyConfig, y as silentLogger } from "./config-
|
|
1
|
+
export { t as CONFIG_FILE_NAME, s as PIPELINE_HEADER, c as SESSION_HEADER, l as TOKEN_HEADER, u as UPSTREAM_HEADER, h as UnsupportedContentError, m as anthropicWalker, _ as composeTransforms, n as configCandidates, g as createSessionFacts, d as createTransformProxy, r as findProxyConfig, i as loadProxyConfig, p as openaiChatWalker, f as openaiResponsesWalker, a as parseProxyConfig, o as resolveProxyConfig, y as silentLogger } from "./config-Ceb5AF_a.mjs";
|
package/dist/omp/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as SESSION_HEADER, i as loadProxyConfig, l as TOKEN_HEADER, n as configCandidates, r as findProxyConfig, u as UPSTREAM_HEADER, v as errorMessage } from "../config-
|
|
1
|
+
import { c as SESSION_HEADER, i as loadProxyConfig, l as TOKEN_HEADER, n as configCandidates, r as findProxyConfig, u as UPSTREAM_HEADER, v as errorMessage } from "../config-Ceb5AF_a.mjs";
|
|
2
2
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
3
3
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
@@ -25,6 +25,8 @@ interface Transform {
|
|
|
25
25
|
};
|
|
26
26
|
/** Called once when the proxy drops the session. */
|
|
27
27
|
dispose?(): void | Promise<void>;
|
|
28
|
+
/** Host-only state of this instance (e.g. the anon mapping), read through TransformProxy.inspect. Never called by the walkers, never sent anywhere. */
|
|
29
|
+
inspect?(): unknown;
|
|
28
30
|
}
|
|
29
31
|
interface SessionFact {
|
|
30
32
|
readonly kind: string;
|
|
@@ -86,6 +88,12 @@ interface TransformProxy {
|
|
|
86
88
|
};
|
|
87
89
|
/** Disposes the session's transform instances and forgets its facts and caches. */
|
|
88
90
|
dropSession(id: string): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Host-only, in-process: each stage's `inspect()` result of the session's pipeline instance, keyed by transform id.
|
|
93
|
+
* `{}` when the session or pipeline is unknown, the instance is not built, or its build failed.
|
|
94
|
+
* Never builds an instance or creates session state; there is no HTTP route for it.
|
|
95
|
+
*/
|
|
96
|
+
inspect(sessionId: string, pipelineId?: string): Promise<Record<string, unknown>>;
|
|
89
97
|
close(): Promise<void>;
|
|
90
98
|
}
|
|
91
99
|
declare const UPSTREAM_HEADER = "x-skaile-transform-upstream";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skaile/transform-proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Same-protocol passthrough proxy that runs model requests and replies through a chain of text transforms (Anthropic Messages, OpenAI chat, OpenAI responses)",
|
|
6
6
|
"license": "MIT",
|