@lucid-agents/pi-xgate 0.1.5 → 0.1.7
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/README.md +103 -7
- package/dist/codec.d.ts +40 -0
- package/dist/codec.js +553 -0
- package/dist/extension.d.ts +16 -0
- package/dist/extension.js +132 -0
- package/dist/generated/openai-model-capabilities.json +847 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/provider.d.ts +24 -0
- package/dist/provider.js +243 -0
- package/dist/taskmarket.d.ts +131 -0
- package/dist/taskmarket.js +275 -0
- package/dist/transport.d.ts +72 -0
- package/dist/transport.js +21 -0
- package/package.json +21 -9
- package/src/codec.ts +117 -26
- package/src/extension.ts +60 -12
- package/src/index.ts +45 -0
- package/src/provider.ts +68 -26
- package/src/taskmarket.ts +484 -0
- package/src/transport.ts +94 -0
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# xgate provider for Pi
|
|
2
2
|
|
|
3
|
-
A Pi
|
|
3
|
+
A Pi provider extension for wallet-paid inference, supported on Pi **1.1.0** and
|
|
4
|
+
**0.85.1**. It uses native
|
|
4
5
|
Anthropic Messages and structured OpenAI Responses through xgate. Pi executes its
|
|
5
6
|
own tools; xgate never executes local tools. Text, tool calls/results and supported
|
|
6
7
|
reasoning signatures survive the full agent loop.
|
|
@@ -9,10 +10,10 @@ reasoning signatures survive the full agent loop.
|
|
|
9
10
|
|
|
10
11
|
The release package is `@lucid-agents/pi-xgate`. It includes the client dependency
|
|
11
12
|
and the reviewed model-capability snapshot; the internal router contracts package
|
|
12
|
-
is not required. With Node 24.19
|
|
13
|
+
is not required. With Node 24.19 or later and Pi 1.1.0:
|
|
13
14
|
|
|
14
15
|
```sh
|
|
15
|
-
pi install npm:@lucid-agents/pi-xgate@0.1.
|
|
16
|
+
pi install npm:@lucid-agents/pi-xgate@0.1.7
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
For repository development before a release is available:
|
|
@@ -23,7 +24,8 @@ pi install ./packages/pi-xgate
|
|
|
23
24
|
```
|
|
24
25
|
|
|
25
26
|
Pi supplies `@earendil-works/pi-ai` and `@earendil-works/pi-coding-agent` as peers.
|
|
26
|
-
This release
|
|
27
|
+
This release supports exactly 1.1.0 and 0.85.1 (the version TaskMarket's agent
|
|
28
|
+
runtime pins); other versions need their own check.
|
|
27
29
|
|
|
28
30
|
## Connect a wallet broker
|
|
29
31
|
|
|
@@ -54,8 +56,21 @@ Both files must be regular, nonsymlink files with no group/other permissions.
|
|
|
54
56
|
Select a model through `/model`. Only the broker policy's models with compatible
|
|
55
57
|
live qualifications are offered. OpenAI requires the new
|
|
56
58
|
`openai-anonymous-tools-v2` router profile; an older server will expose no OpenAI
|
|
57
|
-
coding models. Anthropic requires `anthropic-anonymous-usage-v3`
|
|
58
|
-
`anthropic_no_cache`
|
|
59
|
+
coding models. Anthropic requires `anthropic-anonymous-usage-v3` native Messages
|
|
60
|
+
scopes qualified as `anthropic_no_cache`, `anthropic_ephemeral_5m` or
|
|
61
|
+
`anthropic_ephemeral_1h`.
|
|
62
|
+
|
|
63
|
+
Anthropic caches a prompt only at explicit `cache_control` breakpoints. On a
|
|
64
|
+
cache-qualified scope the provider marks, like Pi's direct Anthropic provider, the
|
|
65
|
+
last tool, the system prompt and the newest user turn (three of Anthropic's four
|
|
66
|
+
breakpoints), so each call in a conversation can read the prefix the previous call
|
|
67
|
+
wrote. Breakpoints are five-minute `ephemeral` writes; Pi's `cacheRetention: "long"`
|
|
68
|
+
selects one-hour writes only on an `anthropic_ephemeral_1h` scope, and
|
|
69
|
+
`cacheRetention: "none"` sends none. An `anthropic_no_cache` scope gets no
|
|
70
|
+
breakpoints, and cache usage it reports is rejected as an invalid result. The
|
|
71
|
+
breakpoints carry no session ID or other key: the provider cache is keyed by the
|
|
72
|
+
content prefix alone. Cache warming stays off, so no unpaid or extra paid call
|
|
73
|
+
is made to keep a cache alive.
|
|
59
74
|
An expired/revoked catalog scope cannot authorize payment just because Pi remembers
|
|
60
75
|
an earlier model list: the provider refreshes before each invocation and the wallet
|
|
61
76
|
client validates the actual quote again.
|
|
@@ -73,6 +88,83 @@ Pi cannot raise the service budget. Authorized ceilings remain consumed after
|
|
|
73
88
|
successful settlement even when most of a deposit is returned. A new budget is an
|
|
74
89
|
explicit wallet-operator action, never automatic rollover or a fresh journal.
|
|
75
90
|
|
|
91
|
+
## Host-injected transport
|
|
92
|
+
|
|
93
|
+
A host that owns payment, such as TaskMarket, builds the provider around its own
|
|
94
|
+
transport instead of the wallet broker. The supported entry point ships built
|
|
95
|
+
JavaScript and type declarations:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import {
|
|
99
|
+
createXgateExtension,
|
|
100
|
+
createXgateProvider,
|
|
101
|
+
type XgateTransport,
|
|
102
|
+
} from "@lucid-agents/pi-xgate";
|
|
103
|
+
|
|
104
|
+
const transport: XgateTransport = {
|
|
105
|
+
models: (signal) => hostCatalog(signal), // router catalog rows
|
|
106
|
+
purchase: (invocation, signal) => hostPurchase(invocation, signal),
|
|
107
|
+
};
|
|
108
|
+
// As a Pi extension: the broker configuration and `/xgate setup` are not used.
|
|
109
|
+
export default createXgateExtension({ transport });
|
|
110
|
+
// Or directly, e.g. for an agent's stream function.
|
|
111
|
+
const provider = await createXgateProvider(transport, {
|
|
112
|
+
sessionId: () => sessionId,
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`createXgateExtension({ transport })` also accepts a factory, called on load and on
|
|
117
|
+
`/xgate refresh`. `/xgate status`, `budget`, `receipts` and `reconcile` use the
|
|
118
|
+
transport's optional methods of the same names. The default extension
|
|
119
|
+
(`@lucid-agents/pi-xgate/extension`, and Pi's `pi.extensions` entry) keeps the
|
|
120
|
+
standalone `BrokerClient`.
|
|
121
|
+
|
|
122
|
+
The provider keeps catalog qualification, native codecs and invocation identity;
|
|
123
|
+
the transport only moves the frozen request and payment. A transport must send at
|
|
124
|
+
most one paid submission per `Invocation.id`, never retry a paid request, reject a
|
|
125
|
+
repeated ID rather than pay again, and resolve only with a verified result.
|
|
126
|
+
`BrokerClient` satisfies this contract.
|
|
127
|
+
|
|
128
|
+
### TaskMarket payer
|
|
129
|
+
|
|
130
|
+
`createTaskMarketTransport` adapts TaskMarket's x402 payer (`@taskmarket/x402-payer`
|
|
131
|
+
API v1). That package is private, so this one declares a structural
|
|
132
|
+
`TaskMarketPayer` (`request`, `status`, `reconcile`) and TaskMarket injects its
|
|
133
|
+
instance. The payer remains the only wallet, signer and payment journal; the
|
|
134
|
+
adapter keeps no payment state.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const transport = createTaskMarketTransport({
|
|
138
|
+
payer, // TaskMarket's X402Payer
|
|
139
|
+
origin: "https://api.xgate.run",
|
|
140
|
+
allocationId, // the agent session's inference allocation
|
|
141
|
+
nonInteractive: true,
|
|
142
|
+
balances: () => allocations.balances(), // optional, for display
|
|
143
|
+
});
|
|
144
|
+
const provider = await createXgateProvider(transport, {
|
|
145
|
+
sessionId: () => sessionId,
|
|
146
|
+
onPaid: (r) => show(r.payment), // network, scheme, asset, atomic amounts, channel
|
|
147
|
+
onPurchaseFailed: (f) => record(f), // original invocation ID, code, pending
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- The Pi invocation ID is the payer `invocationId`. A retried turn reuses it, so
|
|
152
|
+
the payer refuses to send it again (`invocation_duplicate`).
|
|
153
|
+
- The provider refreshes the router catalog (an unpaid `GET /v1/models`) before
|
|
154
|
+
every paid request. The payer's rail echoes the router quote binding and verifies
|
|
155
|
+
settlement.
|
|
156
|
+
- A result is accepted only with a `settled` charge, the Anonymous privacy
|
|
157
|
+
headers and a native JSON body. Every other outcome rejects with
|
|
158
|
+
`XgatePurchaseError`. It is `pending` unless the payer proved no unresolved
|
|
159
|
+
payment; unknown future charge states count as unverified.
|
|
160
|
+
- Pi gets a terminal `error`/`aborted` message naming the original invocation ID,
|
|
161
|
+
worded so Pi's transient-error retry does not fire. Only payer error codes reach
|
|
162
|
+
Pi, never payer messages. Hooks see only `content-type` and `cache-control`.
|
|
163
|
+
- Payment details are rail-neutral (`XgatePayment`): CAIP-2 network, scheme, asset,
|
|
164
|
+
payee, rail kind, authorized and charged atomic amounts, status, reference and,
|
|
165
|
+
for a single matching session deposit, its channel balance. Pi displays them
|
|
166
|
+
and never selects or configures a rail.
|
|
167
|
+
|
|
76
168
|
## Behavior and limits
|
|
77
169
|
|
|
78
170
|
Responses are **buffered**, not token-streamed over the network. After a complete
|
|
@@ -118,7 +210,11 @@ from the current tool set is rejected rather than silently losing that history.
|
|
|
118
210
|
|
|
119
211
|
Run `pnpm pi:check` at the repository root. Tests instantiate Pi's real agent core,
|
|
120
212
|
execute a fixture tool, and verify the next request contains its exact result and
|
|
121
|
-
reasoning history.
|
|
213
|
+
reasoning history. `pnpm packages:check` installs the packed tarballs with Pi 1.1.0
|
|
214
|
+
and 0.85.1 and runs each real Pi CLI through the mock broker and an injected
|
|
215
|
+
transport, type-checks a consumer of the supported exports, and runs the TaskMarket
|
|
216
|
+
payer loop suite (`test/installed-loop.test.ts`: continuation, qualification,
|
|
217
|
+
cancellation, duplicate and lost response) against each installed Pi. Separate wallet tests cover durable financial boundaries.
|
|
122
218
|
These are fixture tests. The [9 October staging campaign](../../docs/validation/pi-client-staging-20261009.md)
|
|
123
219
|
separately exercised the installed Pi CLI with live providers and test tokens.
|
|
124
220
|
That evidence is staging-only; it does not qualify production payment execution.
|
package/dist/codec.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AssistantMessage, Message, Model, SimpleStreamOptions, Tool, Usage } from "@earendil-works/pi-ai";
|
|
2
|
+
import { type Route } from "@lucid-agents/xgate-client/types";
|
|
3
|
+
/** The widest Anthropic prompt-cache write lifetime a scope's qualification permits. */
|
|
4
|
+
export type CacheTtl = "none" | "5m" | "1h";
|
|
5
|
+
export type Entry = {
|
|
6
|
+
model: Model<any>;
|
|
7
|
+
catalog: any;
|
|
8
|
+
route: Route;
|
|
9
|
+
efforts: string[];
|
|
10
|
+
/** Anthropic only: requests may carry `cache_control` breakpoints up to this lifetime. */
|
|
11
|
+
cache: CacheTtl;
|
|
12
|
+
/** Anthropic only: the per-million-token price of a one-hour cache write. */
|
|
13
|
+
cacheWrite1h: number;
|
|
14
|
+
};
|
|
15
|
+
export declare function catalogEntries(rows: any[]): Entry[];
|
|
16
|
+
/**
|
|
17
|
+
* Pi 1.1 passes a normalized transcript; Pi 0.85 passes `systemPrompt` and `tools` beside the
|
|
18
|
+
* messages. Structural, so published types do not name a type only one Pi version has.
|
|
19
|
+
*/
|
|
20
|
+
export type PiContext = {
|
|
21
|
+
messages: Message[];
|
|
22
|
+
systemPrompt?: string;
|
|
23
|
+
tools?: Tool[];
|
|
24
|
+
};
|
|
25
|
+
type Turn = Exclude<Message, {
|
|
26
|
+
role: "system";
|
|
27
|
+
}>;
|
|
28
|
+
export declare function transcript(context: PiContext): {
|
|
29
|
+
system: string;
|
|
30
|
+
tools: Tool[];
|
|
31
|
+
messages: Turn[];
|
|
32
|
+
};
|
|
33
|
+
export declare function encode(entry: Entry, context: PiContext, options?: SimpleStreamOptions): any;
|
|
34
|
+
export declare function decode(entry: Entry, body: any): {
|
|
35
|
+
content: AssistantMessage["content"];
|
|
36
|
+
usage: Usage;
|
|
37
|
+
stopReason: "stop" | "toolUse";
|
|
38
|
+
responseId: string;
|
|
39
|
+
};
|
|
40
|
+
export {};
|