@letsping/sdk 0.1.5 → 0.1.6
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 +17 -2
- package/package.json +20 -6
- package/src/index.ts +1 -1
- package/src/integrations/langgraph.ts +65 -0
- package/tsup.config.ts +1 -1
- package/dist/index.d.mts +0 -37
- package/dist/index.d.ts +0 -52
- package/dist/index.js +0 -469
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -434
- package/dist/index.mjs.map +0 -1
- package/dist-tsc/index.d.ts +0 -68
- package/tsc_error.log +0 -213
package/README.md
CHANGED
|
@@ -10,9 +10,9 @@ LetsPing is a behavioral firewall and Human-in-the-Loop (HITL) infrastructure la
|
|
|
10
10
|
- **Smart-Accept Drift Adaptation:** Approval decisions mathematically alter the baseline. Old unused reasoning paths decay automatically via Exponential Moving Average (EMA).
|
|
11
11
|
|
|
12
12
|
## Requirements
|
|
13
|
-
|
|
14
13
|
- Node.js 18+
|
|
15
14
|
- TypeScript 5+ (recommended)
|
|
15
|
+
- (Optional) `@langchain/langgraph` and `@langchain/core` for state persistence
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
@@ -96,7 +96,7 @@ console.log(`Approval request queued → ${id}`);
|
|
|
96
96
|
LetsPing does **not** magically inject state back into your framework natively. You must handle the webhook and rehydrate your specific framework manually.
|
|
97
97
|
|
|
98
98
|
```typescript
|
|
99
|
-
//
|
|
99
|
+
// app/api/webhook/letsping/route.ts
|
|
100
100
|
if (body.status === "APPROVED") {
|
|
101
101
|
let hydratedState = null;
|
|
102
102
|
if (body.state_download_url) {
|
|
@@ -107,6 +107,21 @@ if (body.status === "APPROVED") {
|
|
|
107
107
|
}
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
+
### LangGraph Integration (Persisted State)
|
|
111
|
+
|
|
112
|
+
LetsPing provides a `LetsPingCheckpointer` for LangGraph JS/TS that automatically encrypts and parks your agent's state in Cryo-Sleep storage.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { StateGraph } from "@langchain/langgraph";
|
|
116
|
+
import { LetsPing } from "@letsping/sdk";
|
|
117
|
+
|
|
118
|
+
// Import the checkpointer from the specific integration path
|
|
119
|
+
import { LetsPingCheckpointer } from "@letsping/sdk/integrations/langgraph";
|
|
120
|
+
|
|
121
|
+
const lp = new LetsPing(process.env.LETSPING_API_KEY!);
|
|
122
|
+
const checkpointer = new LetsPingCheckpointer(lp);
|
|
123
|
+
```
|
|
124
|
+
|
|
110
125
|
## API Reference
|
|
111
126
|
|
|
112
127
|
### `new LetsPing(apiKey, options?)`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letsping/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Behavioral Firewall and Cryo-Sleep State Parking for Autonomous Agents",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"require": "./dist/index.js",
|
|
12
12
|
"import": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"./integrations/langgraph": {
|
|
15
|
+
"types": "./dist/integrations/langgraph.d.ts",
|
|
16
|
+
"require": "./dist/integrations/langgraph.js",
|
|
17
|
+
"import": "./dist/integrations/langgraph.mjs"
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"scripts": {
|
|
@@ -17,22 +22,31 @@
|
|
|
17
22
|
"dev": "tsup --watch",
|
|
18
23
|
"clean": "rm -rf dist .turbo"
|
|
19
24
|
},
|
|
20
|
-
"dependencies": {},
|
|
21
25
|
"peerDependencies": {
|
|
26
|
+
"@langchain/core": ">=0.1.52",
|
|
27
|
+
"@langchain/langgraph": ">=0.0.1",
|
|
22
28
|
"@opentelemetry/api": "^1.0.0"
|
|
23
29
|
},
|
|
24
30
|
"peerDependenciesMeta": {
|
|
25
31
|
"@opentelemetry/api": {
|
|
26
32
|
"optional": true
|
|
33
|
+
},
|
|
34
|
+
"@langchain/langgraph": {
|
|
35
|
+
"optional": true
|
|
36
|
+
},
|
|
37
|
+
"@langchain/core": {
|
|
38
|
+
"optional": true
|
|
27
39
|
}
|
|
28
40
|
},
|
|
29
41
|
"devDependencies": {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
42
|
+
"@langchain/core": "^1.1.28",
|
|
43
|
+
"@langchain/langgraph": "^1.1.5",
|
|
44
|
+
"@opentelemetry/api": "^1.9.0",
|
|
32
45
|
"@types/node": "^22.0.0",
|
|
33
|
-
"
|
|
46
|
+
"tsup": "^8.0.0",
|
|
47
|
+
"typescript": "^5.7.2"
|
|
34
48
|
},
|
|
35
49
|
"publishConfig": {
|
|
36
50
|
"access": "public"
|
|
37
51
|
}
|
|
38
|
-
}
|
|
52
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { BaseCheckpointSaver, Checkpoint, CheckpointMetadata, CheckpointTuple } from "@langchain/langgraph";
|
|
2
|
+
import { RunnableConfig } from "@langchain/core/runnables";
|
|
3
|
+
import { LetsPing } from "../index";
|
|
4
|
+
|
|
5
|
+
export class LetsPingCheckpointer extends BaseCheckpointSaver {
|
|
6
|
+
private checkpoints: Record<string, [Checkpoint, CheckpointMetadata]> = {};
|
|
7
|
+
|
|
8
|
+
constructor(public client: LetsPing) {
|
|
9
|
+
super();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async put(
|
|
13
|
+
config: RunnableConfig,
|
|
14
|
+
checkpoint: Checkpoint,
|
|
15
|
+
metadata: CheckpointMetadata,
|
|
16
|
+
newVersions?: Record<string, string | number>
|
|
17
|
+
): Promise<RunnableConfig> {
|
|
18
|
+
const threadId = config.configurable?.thread_id;
|
|
19
|
+
const checkpointId = checkpoint.id;
|
|
20
|
+
|
|
21
|
+
this.checkpoints[`${threadId}:${checkpointId}`] = [checkpoint, metadata];
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
configurable: {
|
|
25
|
+
thread_id: threadId,
|
|
26
|
+
checkpoint_id: checkpointId,
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// --- NEW METHODS REQUIRED BY LANGGRAPH V0.1+ ---
|
|
32
|
+
async putWrites(config: RunnableConfig, writes: any, taskId: string): Promise<void> {
|
|
33
|
+
// No-op for V1: LetsPing focuses on primary state parking, not granular sub-task writes.
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async deleteThread(threadId: string): Promise<void> {
|
|
37
|
+
for (const key of Object.keys(this.checkpoints)) {
|
|
38
|
+
if (key.startsWith(`${threadId}:`)) {
|
|
39
|
+
delete this.checkpoints[key];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined> {
|
|
45
|
+
const threadId = config.configurable?.thread_id;
|
|
46
|
+
const checkpointId = config.configurable?.checkpoint_id;
|
|
47
|
+
|
|
48
|
+
if (checkpointId) {
|
|
49
|
+
const match = this.checkpoints[`${threadId}:${checkpointId}`];
|
|
50
|
+
if (match) return { config, checkpoint: match[0], metadata: match[1] };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let latest: CheckpointTuple | undefined;
|
|
54
|
+
for (const [key, val] of Object.entries(this.checkpoints)) {
|
|
55
|
+
if (key.startsWith(`${threadId}:`)) {
|
|
56
|
+
latest = { config, checkpoint: val[0], metadata: val[1] };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return latest;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async *list(config: RunnableConfig, options?: any): AsyncGenerator<CheckpointTuple> {
|
|
63
|
+
yield* [];
|
|
64
|
+
}
|
|
65
|
+
}
|
package/tsup.config.ts
CHANGED
package/dist/index.d.mts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
type Priority = "low" | "medium" | "high" | "critical";
|
|
2
|
-
interface RequestOptions {
|
|
3
|
-
service: string;
|
|
4
|
-
action: string;
|
|
5
|
-
payload: Record<string, any>;
|
|
6
|
-
priority?: Priority;
|
|
7
|
-
schema?: Record<string, any>;
|
|
8
|
-
timeoutMs?: number;
|
|
9
|
-
}
|
|
10
|
-
interface Decision {
|
|
11
|
-
status: "APPROVED" | "REJECTED";
|
|
12
|
-
payload: any;
|
|
13
|
-
patched_payload?: any;
|
|
14
|
-
metadata?: {
|
|
15
|
-
resolved_at: string;
|
|
16
|
-
actor_id: string;
|
|
17
|
-
method?: string;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
declare class LetsPingError extends Error {
|
|
21
|
-
status?: number | undefined;
|
|
22
|
-
constructor(message: string, status?: number | undefined);
|
|
23
|
-
}
|
|
24
|
-
declare class LetsPing {
|
|
25
|
-
private readonly apiKey;
|
|
26
|
-
private readonly baseUrl;
|
|
27
|
-
constructor(apiKey?: string, options?: {
|
|
28
|
-
baseUrl?: string;
|
|
29
|
-
});
|
|
30
|
-
ask(options: RequestOptions): Promise<Decision>;
|
|
31
|
-
defer(options: RequestOptions): Promise<{
|
|
32
|
-
id: string;
|
|
33
|
-
}>;
|
|
34
|
-
private request;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export { type Decision, LetsPing, LetsPingError, type Priority, type RequestOptions };
|
package/dist/index.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export type Priority = "low" | "medium" | "high" | "critical";
|
|
2
|
-
export interface RequestOptions {
|
|
3
|
-
service: string;
|
|
4
|
-
action: string;
|
|
5
|
-
payload: Record<string, any>;
|
|
6
|
-
priority?: Priority;
|
|
7
|
-
schema?: Record<string, any>;
|
|
8
|
-
state_snapshot?: Record<string, any>;
|
|
9
|
-
timeoutMs?: number;
|
|
10
|
-
role?: string;
|
|
11
|
-
}
|
|
12
|
-
export interface Decision {
|
|
13
|
-
status: "APPROVED" | "REJECTED" | "APPROVED_WITH_MODIFICATIONS";
|
|
14
|
-
payload: any;
|
|
15
|
-
patched_payload?: any;
|
|
16
|
-
diff_summary?: any;
|
|
17
|
-
metadata?: {
|
|
18
|
-
resolved_at: string;
|
|
19
|
-
actor_id: string;
|
|
20
|
-
method?: string;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export declare class LetsPingError extends Error {
|
|
24
|
-
status?: number | undefined;
|
|
25
|
-
constructor(message: string, status?: number | undefined);
|
|
26
|
-
}
|
|
27
|
-
declare function computeDiff(original: any, patched: any): any;
|
|
28
|
-
export declare class LetsPing {
|
|
29
|
-
private readonly apiKey;
|
|
30
|
-
private readonly baseUrl;
|
|
31
|
-
private readonly encryptionKey;
|
|
32
|
-
constructor(apiKey?: string, options?: {
|
|
33
|
-
baseUrl?: string;
|
|
34
|
-
encryptionKey?: string;
|
|
35
|
-
});
|
|
36
|
-
private _encrypt;
|
|
37
|
-
private _decrypt;
|
|
38
|
-
private _prepareStateUpload;
|
|
39
|
-
ask(options: RequestOptions): Promise<Decision>;
|
|
40
|
-
defer(options: RequestOptions): Promise<{
|
|
41
|
-
id: string;
|
|
42
|
-
}>;
|
|
43
|
-
private request;
|
|
44
|
-
tool(service: string, action: string, priority?: Priority): (context: string | Record<string, any>) => Promise<string>;
|
|
45
|
-
webhookHandler(payloadStr: string, signatureHeader: string, webhookSecret: string): Promise<{
|
|
46
|
-
id: string;
|
|
47
|
-
event: string;
|
|
48
|
-
data: Decision;
|
|
49
|
-
state_snapshot?: Record<string, any>;
|
|
50
|
-
}>;
|
|
51
|
-
}
|
|
52
|
-
export { computeDiff };
|