@threadpoolai/sdk 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +41 -2
- package/dist/index.d.ts +263 -0
- package/dist/index.js +150 -0
- package/package.json +49 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ThreadPool contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @threadpoolai/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Dependency-free TypeScript client for the ThreadPool governance gateway. It asks ThreadPool to authorize each agent step, reports the result, and triggers independent verification. Your agent and its provider credentials stay in your infrastructure.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @threadpoolai/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js 18 or later.
|
|
12
|
+
|
|
13
|
+
## Use
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { ThreadPoolGateway } from "@threadpoolai/sdk";
|
|
17
|
+
|
|
18
|
+
const threadpool = new ThreadPoolGateway({
|
|
19
|
+
baseUrl: process.env.THREADPOOL_URL!,
|
|
20
|
+
apiKey: process.env.THREADPOOL_API_KEY!, // API key with gateway:run
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const { run } = await threadpool.openRun({ title: "Weekly market report" });
|
|
24
|
+
const { step } = await threadpool.declareStep(run.id, {
|
|
25
|
+
capability: "summarization",
|
|
26
|
+
agent: { id: "reporter-v1", name: "Reporter" },
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const result = await threadpool.governed(
|
|
30
|
+
{ runId: run.id, stepId: step.id },
|
|
31
|
+
async () => ({ output: await myAgent.run() }),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (!result.ran) console.log(`Not run: ${result.decision.reason.code}`);
|
|
35
|
+
else console.log(result.verdict.outcome);
|
|
36
|
+
|
|
37
|
+
await threadpool.closeRun(run.id);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`governed()` only calls your function after ThreadPool returns `allow`. A denial or pending approval returns without invoking it. API errors throw `ThreadPoolGatewayError` with HTTP status, API error code, details, and request ID.
|
|
41
|
+
|
|
42
|
+
For endpoint behavior, policies, approval handling, and limits, see the [gateway documentation](https://github.com/ayantik2006/project-innofusion3.0/blob/main/docs/api/gateway.md).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
export type DataSensitivity = "PUBLIC" | "INTERNAL" | "SENSITIVE";
|
|
2
|
+
export interface ApiErrorBody {
|
|
3
|
+
error: {
|
|
4
|
+
code: string;
|
|
5
|
+
message: string;
|
|
6
|
+
details?: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
requestId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface GatewayStep {
|
|
11
|
+
id: string;
|
|
12
|
+
sequence: number;
|
|
13
|
+
capability: string;
|
|
14
|
+
skill: string | null;
|
|
15
|
+
description: string | null;
|
|
16
|
+
status: string;
|
|
17
|
+
agent: {
|
|
18
|
+
id: string;
|
|
19
|
+
reference: string | null;
|
|
20
|
+
name: string;
|
|
21
|
+
status: string;
|
|
22
|
+
} | null;
|
|
23
|
+
attempts: number;
|
|
24
|
+
maxAttempts: number;
|
|
25
|
+
qaScore: number | null;
|
|
26
|
+
outcome: string | null;
|
|
27
|
+
report: {
|
|
28
|
+
outputHash: string;
|
|
29
|
+
outputChars: number;
|
|
30
|
+
reportedAt: string;
|
|
31
|
+
reportedLatencyMs: number | null;
|
|
32
|
+
measuredLatencyMs: number;
|
|
33
|
+
artifactsBytes: number;
|
|
34
|
+
} | null;
|
|
35
|
+
verdict: {
|
|
36
|
+
outputHash: string;
|
|
37
|
+
passed: boolean;
|
|
38
|
+
accepted: boolean;
|
|
39
|
+
score: number;
|
|
40
|
+
threshold: number;
|
|
41
|
+
reason: string;
|
|
42
|
+
issues: string[];
|
|
43
|
+
verifiedBy: "qa_model" | "deterministic_checks" | "deterministic_fallback";
|
|
44
|
+
verifiedByLabel: string;
|
|
45
|
+
verifiedAt: string;
|
|
46
|
+
} | null;
|
|
47
|
+
notDelivered: string | null;
|
|
48
|
+
}
|
|
49
|
+
export interface GatewayRun {
|
|
50
|
+
id: string;
|
|
51
|
+
origin: "gateway";
|
|
52
|
+
originNote: string;
|
|
53
|
+
title: string;
|
|
54
|
+
status: string;
|
|
55
|
+
qualityThreshold: number;
|
|
56
|
+
dataSensitivity: string;
|
|
57
|
+
createdAt: string | null;
|
|
58
|
+
updatedAt: string | null;
|
|
59
|
+
steps: GatewayStep[];
|
|
60
|
+
approvals: Array<{
|
|
61
|
+
id: string;
|
|
62
|
+
kind: string;
|
|
63
|
+
status: string;
|
|
64
|
+
subtaskId: string | null;
|
|
65
|
+
agentId: string | null;
|
|
66
|
+
reasons: unknown[];
|
|
67
|
+
expiresAt: string | null;
|
|
68
|
+
decidedAt: string | null;
|
|
69
|
+
decisionReason: string | null;
|
|
70
|
+
createdAt: string | null;
|
|
71
|
+
}>;
|
|
72
|
+
}
|
|
73
|
+
export interface CredentialScope {
|
|
74
|
+
id: string;
|
|
75
|
+
operations: string[];
|
|
76
|
+
expiresAt: string;
|
|
77
|
+
maxUses: number;
|
|
78
|
+
usesRemaining: number;
|
|
79
|
+
scope: {
|
|
80
|
+
runId: string;
|
|
81
|
+
stepId: string;
|
|
82
|
+
agentId: string;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export type AuthorizeResponse = {
|
|
86
|
+
decision: "allow";
|
|
87
|
+
reason: {
|
|
88
|
+
code: "authorized";
|
|
89
|
+
message: string;
|
|
90
|
+
};
|
|
91
|
+
credential: CredentialScope;
|
|
92
|
+
assignmentId: string;
|
|
93
|
+
step: GatewayStep;
|
|
94
|
+
} | {
|
|
95
|
+
decision: "deny";
|
|
96
|
+
reason: {
|
|
97
|
+
code: string;
|
|
98
|
+
message: string;
|
|
99
|
+
ruleIds?: string[];
|
|
100
|
+
};
|
|
101
|
+
agentRevoked: boolean;
|
|
102
|
+
step: GatewayStep;
|
|
103
|
+
} | {
|
|
104
|
+
decision: "pending_approval";
|
|
105
|
+
reason: {
|
|
106
|
+
code: "awaiting_human_approval";
|
|
107
|
+
message: string;
|
|
108
|
+
};
|
|
109
|
+
approval: {
|
|
110
|
+
id: string;
|
|
111
|
+
expiresAt: string;
|
|
112
|
+
reasons: string[];
|
|
113
|
+
};
|
|
114
|
+
step: GatewayStep;
|
|
115
|
+
};
|
|
116
|
+
export interface ReportResponse {
|
|
117
|
+
step: GatewayStep;
|
|
118
|
+
report: {
|
|
119
|
+
outputHash: string;
|
|
120
|
+
outputChars: number;
|
|
121
|
+
measuredLatencyMs: number;
|
|
122
|
+
reportedLatencyMs: number | null;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
export interface VerifyResponse {
|
|
126
|
+
verdict: {
|
|
127
|
+
passed: boolean;
|
|
128
|
+
accepted: boolean;
|
|
129
|
+
score: number;
|
|
130
|
+
threshold: number;
|
|
131
|
+
reason: string;
|
|
132
|
+
issues: string[];
|
|
133
|
+
verifiedBy: "qa_model" | "deterministic_checks" | "deterministic_fallback";
|
|
134
|
+
verifiedByLabel: string;
|
|
135
|
+
outputHash: string;
|
|
136
|
+
note: string;
|
|
137
|
+
};
|
|
138
|
+
outcome: "accepted" | "rejected";
|
|
139
|
+
outcomeReason: string;
|
|
140
|
+
attemptsUsed: number;
|
|
141
|
+
attemptsRemaining: number;
|
|
142
|
+
step: GatewayStep;
|
|
143
|
+
}
|
|
144
|
+
export interface CloseResponse {
|
|
145
|
+
run: GatewayRun;
|
|
146
|
+
summary: {
|
|
147
|
+
steps: number;
|
|
148
|
+
accepted: number;
|
|
149
|
+
rejected: number;
|
|
150
|
+
unknown: number;
|
|
151
|
+
notAuthorized: number;
|
|
152
|
+
};
|
|
153
|
+
accountability: unknown;
|
|
154
|
+
receipt: {
|
|
155
|
+
hash: string;
|
|
156
|
+
body: unknown;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
export interface OpenRunInput {
|
|
160
|
+
title: string;
|
|
161
|
+
qualityThreshold?: number;
|
|
162
|
+
dataSensitivity?: DataSensitivity;
|
|
163
|
+
}
|
|
164
|
+
export interface DeclareStepInput {
|
|
165
|
+
capability: string;
|
|
166
|
+
skill?: string;
|
|
167
|
+
description?: string;
|
|
168
|
+
/** Your own identifier for the agent (stable across runs) and a display name. */
|
|
169
|
+
agent: {
|
|
170
|
+
id: string;
|
|
171
|
+
name: string;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
export interface ReportInput {
|
|
175
|
+
credentialId: string;
|
|
176
|
+
output: string;
|
|
177
|
+
artifacts?: Record<string, unknown>;
|
|
178
|
+
/** Your own measurement. ThreadPool records it as reported; it measures latency itself. */
|
|
179
|
+
latencyMs?: number;
|
|
180
|
+
}
|
|
181
|
+
/** The raw API answer, exactly as ThreadPool sent it. */
|
|
182
|
+
export interface RawResponse {
|
|
183
|
+
ok: boolean;
|
|
184
|
+
status: number;
|
|
185
|
+
body: unknown;
|
|
186
|
+
}
|
|
187
|
+
export declare class ThreadPoolGatewayError extends Error {
|
|
188
|
+
readonly status: number;
|
|
189
|
+
readonly code: string;
|
|
190
|
+
readonly details?: Record<string, unknown> | undefined;
|
|
191
|
+
readonly requestId?: string | undefined;
|
|
192
|
+
constructor(status: number, code: string, message: string, details?: Record<string, unknown> | undefined, requestId?: string | undefined);
|
|
193
|
+
}
|
|
194
|
+
export interface ThreadPoolGatewayOptions {
|
|
195
|
+
/** Your ThreadPool deployment, e.g. https://threadpool.example.com */
|
|
196
|
+
baseUrl: string;
|
|
197
|
+
/** An organization API key with the gateway:run scope. */
|
|
198
|
+
apiKey: string;
|
|
199
|
+
fetch?: typeof fetch;
|
|
200
|
+
/** Generates the Idempotency-Key for each write. Defaults to a random UUID. */
|
|
201
|
+
idempotencyKey?: () => string;
|
|
202
|
+
/** Retries of a write after a network error, a 5xx or "still processing", with the SAME key. Default 2. */
|
|
203
|
+
retries?: number;
|
|
204
|
+
/** Delay between retries in ms (doubles each time). Default 500. */
|
|
205
|
+
retryDelayMs?: number;
|
|
206
|
+
}
|
|
207
|
+
export type GatewayOperation = "open_run" | "get_run" | "declare_step" | "authorize_step" | "report_step" | "verify_step" | "close_run";
|
|
208
|
+
export interface GovernedStep {
|
|
209
|
+
runId: string;
|
|
210
|
+
stepId: string;
|
|
211
|
+
}
|
|
212
|
+
/** What your function returns: the output text, optionally with artifacts. */
|
|
213
|
+
export type GovernedOutput = string | {
|
|
214
|
+
output: string;
|
|
215
|
+
artifacts?: Record<string, unknown>;
|
|
216
|
+
};
|
|
217
|
+
export type GovernedResult = {
|
|
218
|
+
ran: false;
|
|
219
|
+
decision: Extract<AuthorizeResponse, {
|
|
220
|
+
decision: "deny" | "pending_approval";
|
|
221
|
+
}>;
|
|
222
|
+
} | {
|
|
223
|
+
ran: true;
|
|
224
|
+
decision: Extract<AuthorizeResponse, {
|
|
225
|
+
decision: "allow";
|
|
226
|
+
}>;
|
|
227
|
+
report: ReportResponse;
|
|
228
|
+
verdict: VerifyResponse;
|
|
229
|
+
};
|
|
230
|
+
export declare class ThreadPoolGateway {
|
|
231
|
+
private readonly baseUrl;
|
|
232
|
+
private readonly apiKey;
|
|
233
|
+
private readonly fetchImpl;
|
|
234
|
+
private readonly newKey;
|
|
235
|
+
private readonly retries;
|
|
236
|
+
private readonly retryDelayMs;
|
|
237
|
+
constructor(options: ThreadPoolGatewayOptions);
|
|
238
|
+
call(operation: GatewayOperation, args?: Record<string, unknown>): Promise<RawResponse>;
|
|
239
|
+
private send;
|
|
240
|
+
private unwrap;
|
|
241
|
+
openRun(input: OpenRunInput): Promise<{
|
|
242
|
+
run: GatewayRun;
|
|
243
|
+
}>;
|
|
244
|
+
getRun(runId: string): Promise<{
|
|
245
|
+
run: GatewayRun;
|
|
246
|
+
}>;
|
|
247
|
+
declareStep(runId: string, input: DeclareStepInput): Promise<{
|
|
248
|
+
step: GatewayStep;
|
|
249
|
+
}>;
|
|
250
|
+
/** Ask before acting. allow | deny | pending_approval - all answers, not errors. */
|
|
251
|
+
authorizeStep(runId: string, stepId: string): Promise<AuthorizeResponse>;
|
|
252
|
+
reportStep(runId: string, stepId: string, input: ReportInput): Promise<ReportResponse>;
|
|
253
|
+
verifyStep(runId: string, stepId: string): Promise<VerifyResponse>;
|
|
254
|
+
closeRun(runId: string): Promise<CloseResponse>;
|
|
255
|
+
/**
|
|
256
|
+
* Authorize, run `fn`, report and verify. `fn` runs ONLY on "allow"; on
|
|
257
|
+
* "deny" or "pending_approval" it is never called and the decision is
|
|
258
|
+
* returned (ask again later for a pending approval). If `fn` throws, nothing
|
|
259
|
+
* is reported: the authorization lapses at its expiry and the step's record
|
|
260
|
+
* shows "unknown", never a guess.
|
|
261
|
+
*/
|
|
262
|
+
governed(step: GovernedStep, fn: (credential: CredentialScope) => Promise<GovernedOutput>): Promise<GovernedResult>;
|
|
263
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// @threadpoolai/sdk - a small, dependency-free client for ThreadPool's governance
|
|
2
|
+
// gateway (/api/v1/gateway). Your agents keep running where they run today;
|
|
3
|
+
// ThreadPool authorizes each step, verifies what your agent produced, and
|
|
4
|
+
// records who did what under which authority.
|
|
5
|
+
//
|
|
6
|
+
// The client holds no governance logic: every decision (allow, deny,
|
|
7
|
+
// pending_approval, the QA verdict) is made by ThreadPool and returned as-is.
|
|
8
|
+
// It never sends your model traffic or provider keys anywhere: it sends only
|
|
9
|
+
// what you pass it.
|
|
10
|
+
//
|
|
11
|
+
// const tp = new ThreadPoolGateway({ baseUrl, apiKey }); // key scope: gateway:run
|
|
12
|
+
// const { run } = await tp.openRun({ title: "Weekly market report" });
|
|
13
|
+
// const { step } = await tp.declareStep(run.id, { capability: "web_research", agent: { id: "researcher-v2", name: "Researcher" } });
|
|
14
|
+
// const result = await tp.governed({ runId: run.id, stepId: step.id }, async () => myAgent.research("..."));
|
|
15
|
+
// if (!result.ran) console.log("refused:", result.decision.reason);
|
|
16
|
+
// await tp.closeRun(run.id);
|
|
17
|
+
export class ThreadPoolGatewayError extends Error {
|
|
18
|
+
status;
|
|
19
|
+
code;
|
|
20
|
+
details;
|
|
21
|
+
requestId;
|
|
22
|
+
constructor(status, code, message, details, requestId) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.status = status;
|
|
25
|
+
this.code = code;
|
|
26
|
+
this.details = details;
|
|
27
|
+
this.requestId = requestId;
|
|
28
|
+
this.name = "ThreadPoolGatewayError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
32
|
+
export class ThreadPoolGateway {
|
|
33
|
+
baseUrl;
|
|
34
|
+
apiKey;
|
|
35
|
+
fetchImpl;
|
|
36
|
+
newKey;
|
|
37
|
+
retries;
|
|
38
|
+
retryDelayMs;
|
|
39
|
+
constructor(options) {
|
|
40
|
+
if (!options.apiKey)
|
|
41
|
+
throw new Error("ThreadPoolGateway: apiKey is required (a key with the gateway:run scope).");
|
|
42
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
43
|
+
this.apiKey = options.apiKey;
|
|
44
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
45
|
+
this.newKey = options.idempotencyKey ?? (() => `tpsdk_${globalThis.crypto.randomUUID()}`);
|
|
46
|
+
this.retries = options.retries ?? 2;
|
|
47
|
+
this.retryDelayMs = options.retryDelayMs ?? 500;
|
|
48
|
+
}
|
|
49
|
+
// ── Raw calls: the API's answer verbatim (used by the MCP server) ──────
|
|
50
|
+
async call(operation, args = {}) {
|
|
51
|
+
const runId = typeof args.runId === "string" ? encodeURIComponent(args.runId) : "";
|
|
52
|
+
const stepId = typeof args.stepId === "string" ? encodeURIComponent(args.stepId) : "";
|
|
53
|
+
const { runId: _r, stepId: _s, ...body } = args;
|
|
54
|
+
void _r;
|
|
55
|
+
void _s;
|
|
56
|
+
switch (operation) {
|
|
57
|
+
case "open_run":
|
|
58
|
+
return this.send("POST", "/api/v1/gateway/runs", body);
|
|
59
|
+
case "get_run":
|
|
60
|
+
return this.send("GET", `/api/v1/gateway/runs/${runId}`);
|
|
61
|
+
case "declare_step":
|
|
62
|
+
return this.send("POST", `/api/v1/gateway/runs/${runId}/steps`, body);
|
|
63
|
+
case "authorize_step":
|
|
64
|
+
return this.send("POST", `/api/v1/gateway/runs/${runId}/steps/${stepId}/authorize`, {});
|
|
65
|
+
case "report_step":
|
|
66
|
+
return this.send("POST", `/api/v1/gateway/runs/${runId}/steps/${stepId}/report`, body);
|
|
67
|
+
case "verify_step":
|
|
68
|
+
return this.send("POST", `/api/v1/gateway/runs/${runId}/steps/${stepId}/verify`, {});
|
|
69
|
+
case "close_run":
|
|
70
|
+
return this.send("POST", `/api/v1/gateway/runs/${runId}/close`, {});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async send(method, path, body) {
|
|
74
|
+
const headers = { authorization: `Bearer ${this.apiKey}`, accept: "application/json" };
|
|
75
|
+
if (method === "POST") {
|
|
76
|
+
headers["content-type"] = "application/json";
|
|
77
|
+
// One key per logical write, reused on every retry of it.
|
|
78
|
+
headers["idempotency-key"] = this.newKey();
|
|
79
|
+
}
|
|
80
|
+
let attempt = 0;
|
|
81
|
+
for (;;) {
|
|
82
|
+
try {
|
|
83
|
+
const res = await this.fetchImpl(`${this.baseUrl}${path}`, { method, headers, body: method === "POST" ? JSON.stringify(body ?? {}) : undefined });
|
|
84
|
+
const parsed = await res.json().catch(() => null);
|
|
85
|
+
const stillProcessing = res.status === 409 && parsed?.error?.code === "CONFLICT" && /still being processed/i.test(parsed.error.message);
|
|
86
|
+
if ((res.status >= 500 || stillProcessing) && attempt < this.retries) {
|
|
87
|
+
attempt += 1;
|
|
88
|
+
await sleep(this.retryDelayMs * 2 ** (attempt - 1));
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
return { ok: res.ok, status: res.status, body: parsed };
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
if (attempt >= this.retries)
|
|
95
|
+
throw err;
|
|
96
|
+
attempt += 1;
|
|
97
|
+
await sleep(this.retryDelayMs * 2 ** (attempt - 1));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async unwrap(response) {
|
|
102
|
+
const r = await response;
|
|
103
|
+
if (r.ok)
|
|
104
|
+
return r.body;
|
|
105
|
+
const e = r.body?.error;
|
|
106
|
+
throw new ThreadPoolGatewayError(r.status, e?.code ?? "UNKNOWN", e?.message ?? `HTTP ${r.status}`, e?.details, r.body?.requestId);
|
|
107
|
+
}
|
|
108
|
+
// ── The calls ──────────────────────────────────────────────────────────
|
|
109
|
+
openRun(input) {
|
|
110
|
+
return this.unwrap(this.call("open_run", { ...input }));
|
|
111
|
+
}
|
|
112
|
+
getRun(runId) {
|
|
113
|
+
return this.unwrap(this.call("get_run", { runId }));
|
|
114
|
+
}
|
|
115
|
+
declareStep(runId, input) {
|
|
116
|
+
return this.unwrap(this.call("declare_step", { runId, ...input }));
|
|
117
|
+
}
|
|
118
|
+
/** Ask before acting. allow | deny | pending_approval - all answers, not errors. */
|
|
119
|
+
authorizeStep(runId, stepId) {
|
|
120
|
+
return this.unwrap(this.call("authorize_step", { runId, stepId }));
|
|
121
|
+
}
|
|
122
|
+
reportStep(runId, stepId, input) {
|
|
123
|
+
return this.unwrap(this.call("report_step", { runId, stepId, ...input }));
|
|
124
|
+
}
|
|
125
|
+
verifyStep(runId, stepId) {
|
|
126
|
+
return this.unwrap(this.call("verify_step", { runId, stepId }));
|
|
127
|
+
}
|
|
128
|
+
closeRun(runId) {
|
|
129
|
+
return this.unwrap(this.call("close_run", { runId }));
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Authorize, run `fn`, report and verify. `fn` runs ONLY on "allow"; on
|
|
133
|
+
* "deny" or "pending_approval" it is never called and the decision is
|
|
134
|
+
* returned (ask again later for a pending approval). If `fn` throws, nothing
|
|
135
|
+
* is reported: the authorization lapses at its expiry and the step's record
|
|
136
|
+
* shows "unknown", never a guess.
|
|
137
|
+
*/
|
|
138
|
+
async governed(step, fn) {
|
|
139
|
+
const decision = await this.authorizeStep(step.runId, step.stepId);
|
|
140
|
+
if (decision.decision !== "allow")
|
|
141
|
+
return { ran: false, decision };
|
|
142
|
+
const started = Date.now();
|
|
143
|
+
const produced = await fn(decision.credential);
|
|
144
|
+
const latencyMs = Date.now() - started;
|
|
145
|
+
const { output, artifacts } = typeof produced === "string" ? { output: produced, artifacts: undefined } : produced;
|
|
146
|
+
const report = await this.reportStep(step.runId, step.stepId, { credentialId: decision.credential.id, output, ...(artifacts ? { artifacts } : {}), latencyMs });
|
|
147
|
+
const verdict = await this.verifyStep(step.runId, step.stepId);
|
|
148
|
+
return { ran: true, decision, report, verdict };
|
|
149
|
+
}
|
|
150
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@threadpoolai/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@threadpoolai/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Client for ThreadPool's governance gateway: scoped authority, independent QA and an accountability record for agents you run yourself.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.build.json",
|
|
22
|
+
"prepack": "npm run build",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"keywords": [
|
|
31
|
+
"threadpool",
|
|
32
|
+
"ai-agents",
|
|
33
|
+
"agent-governance",
|
|
34
|
+
"governance",
|
|
35
|
+
"mcp"
|
|
36
|
+
],
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/ayantik2006/project-innofusion3.0.git",
|
|
40
|
+
"directory": "packages/sdk"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/ayantik2006/project-innofusion3.0/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/ayantik2006/project-innofusion3.0#readme",
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
}
|
|
49
|
+
}
|