@open-pets/dsh 3.3.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/cordis.patch.yml +3 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/runtime.d.ts +32 -0
- package/dist/runtime.js +104 -0
- package/package.json +60 -0
package/cordis.patch.yml
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
export { classifyDshEvent, createOpenPetsDshClient, createOpenPetsDshRuntime, registerDshListeners, type DshCordisApi, type DshAgentStatus, type DshEventName, type DshEventDecision, type OpenPetsDshOptions, type OpenPetsDshRuntime, } from "./runtime.js";
|
|
3
|
+
import { type OpenPetsDshOptions } from "./runtime.js";
|
|
4
|
+
export declare const name = "@open-pets/dsh";
|
|
5
|
+
/** Install the OpenPets listeners into the DSH Cordis context. */
|
|
6
|
+
export declare function apply(ctx: Context, options?: OpenPetsDshOptions): void;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { classifyDshEvent, createOpenPetsDshClient, createOpenPetsDshRuntime, registerDshListeners, } from "./runtime.js";
|
|
2
|
+
import { registerDshListeners } from "./runtime.js";
|
|
3
|
+
export const name = "@open-pets/dsh";
|
|
4
|
+
/** Install the OpenPets listeners into the DSH Cordis context. */
|
|
5
|
+
export function apply(ctx, options = {}) {
|
|
6
|
+
registerDshListeners(ctx, options);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type HookSpeechCategory } from "@open-pets/agent-events";
|
|
2
|
+
import { type OpenPetsClient, type OpenPetsReaction } from "@open-pets/client";
|
|
3
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
4
|
+
export type DshEventName = "agent/status" | "agent/error" | "approval/request";
|
|
5
|
+
export type DshAgentStatus = "running" | "idle";
|
|
6
|
+
export interface DshEventDecision {
|
|
7
|
+
readonly reaction: OpenPetsReaction;
|
|
8
|
+
readonly speechCategory: HookSpeechCategory;
|
|
9
|
+
}
|
|
10
|
+
export interface OpenPetsDshOptions {
|
|
11
|
+
readonly clientFactory?: () => OpenPetsClient;
|
|
12
|
+
readonly schedule?: (work: () => Promise<void>) => void | Promise<void>;
|
|
13
|
+
readonly random?: () => number;
|
|
14
|
+
readonly now?: () => number;
|
|
15
|
+
}
|
|
16
|
+
export interface OpenPetsDshRuntime {
|
|
17
|
+
readonly handleStatus: (event: unknown) => void;
|
|
18
|
+
readonly handleEvent: (eventName: DshEventName, event?: unknown) => void;
|
|
19
|
+
readonly handleApproval: () => void;
|
|
20
|
+
}
|
|
21
|
+
export type DshCordisApi = Pick<Context, "on">;
|
|
22
|
+
/**
|
|
23
|
+
* Map only the categorical values defined by DSH. Event payloads are
|
|
24
|
+
* deliberately not inspected or forwarded. For agent/status, only the
|
|
25
|
+
* categorical `status` property is read from the event envelope.
|
|
26
|
+
*/
|
|
27
|
+
export declare function classifyDshEvent(eventName: DshEventName | string, event?: unknown): DshEventDecision | undefined;
|
|
28
|
+
export declare function createOpenPetsDshRuntime(options?: OpenPetsDshOptions): OpenPetsDshRuntime;
|
|
29
|
+
export declare function createOpenPetsDshClient(): OpenPetsClient;
|
|
30
|
+
/** Register the three DSH listeners without taking ownership of their flow. */
|
|
31
|
+
export declare function registerDshListeners(cordis: DshCordisApi, options?: OpenPetsDshOptions): OpenPetsDshRuntime;
|
|
32
|
+
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { pickHookSpeech, validateHookSpeech } from "@open-pets/agent-events";
|
|
2
|
+
import { createOpenPetsClient } from "@open-pets/client";
|
|
3
|
+
const automaticTimeoutMs = 500;
|
|
4
|
+
const errorSuccessSuppressionMs = 5_000;
|
|
5
|
+
/**
|
|
6
|
+
* Map only the categorical values defined by DSH. Event payloads are
|
|
7
|
+
* deliberately not inspected or forwarded. For agent/status, only the
|
|
8
|
+
* categorical `status` property is read from the event envelope.
|
|
9
|
+
*/
|
|
10
|
+
export function classifyDshEvent(eventName, event) {
|
|
11
|
+
if (eventName === "agent/status") {
|
|
12
|
+
const status = typeof event === "string" ? event : getStatusCategory(event);
|
|
13
|
+
if (status === "running")
|
|
14
|
+
return { reaction: "thinking", speechCategory: "thinking" };
|
|
15
|
+
if (status === "idle")
|
|
16
|
+
return { reaction: "success", speechCategory: "success" };
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
if (eventName === "agent/error")
|
|
20
|
+
return { reaction: "error", speechCategory: "error" };
|
|
21
|
+
if (eventName === "approval/request")
|
|
22
|
+
return { reaction: "waiting", speechCategory: "permission" };
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
export function createOpenPetsDshRuntime(options = {}) {
|
|
26
|
+
const clientFactory = options.clientFactory ?? createOpenPetsDshClient;
|
|
27
|
+
const schedule = options.schedule ?? defaultSchedule;
|
|
28
|
+
let client;
|
|
29
|
+
let recentErrorAt = Number.NEGATIVE_INFINITY;
|
|
30
|
+
const getClient = () => {
|
|
31
|
+
client ??= clientFactory();
|
|
32
|
+
return client;
|
|
33
|
+
};
|
|
34
|
+
const dispatch = (decision) => {
|
|
35
|
+
if (!decision)
|
|
36
|
+
return;
|
|
37
|
+
const now = options.now?.() ?? Date.now();
|
|
38
|
+
if (decision.reaction === "error") {
|
|
39
|
+
recentErrorAt = now;
|
|
40
|
+
}
|
|
41
|
+
else if (decision.reaction === "success" && now - recentErrorAt < errorSuccessSuppressionMs) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const work = async () => {
|
|
45
|
+
try {
|
|
46
|
+
const speech = validateHookSpeech(pickHookSpeech(decision.speechCategory, options.random));
|
|
47
|
+
await getClient().say(speech, { reaction: decision.reaction });
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Automatic agent listeners must never affect the DSH operation.
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
try {
|
|
54
|
+
const scheduled = schedule(work);
|
|
55
|
+
if (isPromiseLike(scheduled))
|
|
56
|
+
void scheduled.catch(() => undefined);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// A scheduler supplied by the host is optional infrastructure.
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
handleStatus(event) {
|
|
64
|
+
dispatch(classifyDshEvent("agent/status", event));
|
|
65
|
+
},
|
|
66
|
+
handleEvent(eventName, event) {
|
|
67
|
+
dispatch(classifyDshEvent(eventName, event));
|
|
68
|
+
},
|
|
69
|
+
handleApproval() {
|
|
70
|
+
dispatch(classifyDshEvent("approval/request"));
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function createOpenPetsDshClient() {
|
|
75
|
+
return createOpenPetsClient({
|
|
76
|
+
remote: false,
|
|
77
|
+
connectTimeoutMs: automaticTimeoutMs,
|
|
78
|
+
responseTimeoutMs: automaticTimeoutMs,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** Register the three DSH listeners without taking ownership of their flow. */
|
|
82
|
+
export function registerDshListeners(cordis, options = {}) {
|
|
83
|
+
const runtime = createOpenPetsDshRuntime(options);
|
|
84
|
+
const on = cordis.on;
|
|
85
|
+
on("agent/status", (event) => runtime.handleStatus(event));
|
|
86
|
+
on("agent/error", () => runtime.handleEvent("agent/error"));
|
|
87
|
+
on("approval/request", (_request, next) => {
|
|
88
|
+
runtime.handleApproval();
|
|
89
|
+
return typeof next === "function" ? next() : undefined;
|
|
90
|
+
});
|
|
91
|
+
return runtime;
|
|
92
|
+
}
|
|
93
|
+
function defaultSchedule(work) {
|
|
94
|
+
void Promise.resolve().then(work).catch(() => undefined);
|
|
95
|
+
}
|
|
96
|
+
function isPromiseLike(value) {
|
|
97
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
98
|
+
}
|
|
99
|
+
function getStatusCategory(event) {
|
|
100
|
+
if (typeof event !== "object" || event === null)
|
|
101
|
+
return undefined;
|
|
102
|
+
return event.status;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=runtime.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@open-pets/dsh",
|
|
3
|
+
"version": "3.3.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/alvinunreal/openpets.git",
|
|
8
|
+
"directory": "packages/dsh"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"dsh",
|
|
13
|
+
"cordis",
|
|
14
|
+
"openpets",
|
|
15
|
+
"coding-agent"
|
|
16
|
+
],
|
|
17
|
+
"main": "dist/index.js",
|
|
18
|
+
"types": "dist/index.d.ts",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/index.d.ts",
|
|
21
|
+
"dist/index.js",
|
|
22
|
+
"dist/runtime.d.ts",
|
|
23
|
+
"dist/runtime.js",
|
|
24
|
+
"cordis.patch.yml"
|
|
25
|
+
],
|
|
26
|
+
"dsh": {
|
|
27
|
+
"bundle": {
|
|
28
|
+
"patch": "./cordis.patch.yml"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"default": "./dist/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
40
|
+
"./package.json": "./package.json"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"test": "node dist/runtime.test.js && node dist/check-dsh.js",
|
|
44
|
+
"check": "pnpm typecheck && pnpm build && pnpm test",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"build": "tsc"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@open-pets/agent-events": "workspace:*",
|
|
50
|
+
"@open-pets/client": "workspace:*"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@deepseek-ai/cordis": "^4.0.1"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
57
|
+
"@types/node": "^25.6.2",
|
|
58
|
+
"typescript": "^6.0.3"
|
|
59
|
+
}
|
|
60
|
+
}
|