@hasna-internal/kai-session-checkpoint-policy 0.1.1-rc.2
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.i18n.yaml +6 -0
- package/README.md +45 -0
- package/README.zh.md +45 -0
- package/lib/index.js +78 -0
- package/lib/invariant.js +23 -0
- package/lib/types/index.d.ts +23 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
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.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/session/session-checkpoint-policy/README.md
|
|
5
|
+
README.md: 01ed3c694967b1a86245d01b9d9f7eecd1193348
|
|
6
|
+
README.zh.md: e2c197c0cc1d942a045c1ea22c1fb257f6e4059d
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# dsh-session-checkpoint-policy
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Semantic durability policy for persisted agents. It checkpoints the event-sourced session before a model adapter receives a request, before a top-level tool body may produce an external side effect, and at each `agent/pre-step` boundary so the preceding response and ordered tool results are durable before the next request.
|
|
6
|
+
|
|
7
|
+
## Plugin (namespace: `session-checkpoint-policy`)
|
|
8
|
+
|
|
9
|
+
This zero-config function plugin consumes `ctx.sessions`, `ctx.llm`, `ctx.tools`, and the presence of `ctx.sessionPersistence`. Load it beside one persistence backend:
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
- id: session-persistence
|
|
13
|
+
name: '@hasna-internal/kai-session-persistence-jsonl'
|
|
14
|
+
|
|
15
|
+
- id: session-checkpoints
|
|
16
|
+
name: '@hasna-internal/kai-session-checkpoint-policy'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Persistence and checkpoint scheduling are intentionally separate Cordis plugins. A persistence backend starts bounded background batches for `session/event` appends and makes each requested `session/flush` an immediate quiescence barrier; this policy chooses the request, tool-dispatch, and next-step barriers. Loading a backend without this policy is valid, but a crash may lose events still inside the configured batching window or an outstanding write. First-party persisted apps and runtimes mount both plugins explicitly; a specialized deployment may deliberately omit or replace the policy.
|
|
20
|
+
|
|
21
|
+
The policy wraps `llm/stream` lazily, so the downstream stream is not constructed until the live session's buffered request events are durable. It wraps `tools/execute` after pre-execute policy and guards; a top-level tool body runs only after its recorded call is durable. If cancellation lands while that flush is pending, the wrapper returns the canonical `ABORTED_BEFORE_DISPATCH` result without entering the tool body. Nested tool dispatches reuse the outer model-visible call's checkpoint. `agent/pre-step` persists the preceding response/result batch before request derivation.
|
|
22
|
+
|
|
23
|
+
Checkpoint rejection is fail-closed at the model and tool boundaries: neither the adapter nor the top-level tool body runs. A step-boundary rejection fails the turn before another request starts. Concurrent tool checkpoints share the session store's serialized persistence drain and cannot duplicate sequence numbers.
|
|
24
|
+
|
|
25
|
+
## Model Experience
|
|
26
|
+
|
|
27
|
+
### Interrupted calls
|
|
28
|
+
|
|
29
|
+
#### What the model sees
|
|
30
|
+
|
|
31
|
+
The plugin adds no prompt or tool schema. A hard crash after a tool checkpoint but before its result leaves a durable unmatched call; session recovery supplies the model-visible `TOOL_OUTCOME_UNKNOWN` result owned by `dsh-session`. The message permits retry for read-only or idempotent work and requires state verification or user confirmation for calls that may have side effects.
|
|
32
|
+
|
|
33
|
+
#### Token effect
|
|
34
|
+
|
|
35
|
+
Successful checkpoints add no tokens and do not change the request. Recovery adds one short tool-result message to balance the interrupted transcript.
|
|
36
|
+
|
|
37
|
+
#### KV Cache effect
|
|
38
|
+
|
|
39
|
+
The repair result is appended after the reusable prefix, so it does not invalidate earlier cache entries.
|
|
40
|
+
|
|
41
|
+
## Known Limitations and Deferred Work
|
|
42
|
+
|
|
43
|
+
- The policy durably records execution intent, not generic exactly-once effects. Side-effecting tools should forward `exec.callId` as an idempotency key when their provider supports one.
|
|
44
|
+
- Streaming `assistant/chunk` events have no per-chunk checkpoint. Bounded background batches normally persist them before the next semantic checkpoint, but a hard crash may lose the current in-memory batch or outstanding write.
|
|
45
|
+
- A persisted call without a result cannot prove whether its external effect completed. Recovery therefore records an unknown outcome instead of retrying automatically.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# dsh-session-checkpoint-policy
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
已持久化的 agent(智能体)的语义持久性策略。它会在模型适配器收到请求前、顶层工具正文可产生外部副作用前,以及每个 `agent/pre-step` 边界为事件溯源会话创建检查点,使前一响应与有序工具结果在下一个请求前已持久化。
|
|
6
|
+
|
|
7
|
+
## 插件(命名空间:`session-checkpoint-policy`)
|
|
8
|
+
|
|
9
|
+
该零配置函数插件消费 `ctx.sessions`、`ctx.llm`、`ctx.tools` 以及 `ctx.sessionPersistence` 的存在性。将其与一个持久化后端一起加载:
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
- id: session-persistence
|
|
13
|
+
name: '@hasna-internal/kai-session-persistence-jsonl'
|
|
14
|
+
|
|
15
|
+
- id: session-checkpoints
|
|
16
|
+
name: '@hasna-internal/kai-session-checkpoint-policy'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
持久化与检查点调度刻意拆分为独立 Cordis 插件。持久化后端会为追加的 `session/event` 启动有界后台批次,并把每个已请求的 `session/flush` 变成即时完全停稳屏障;该策略选择请求、工具分派和下一步骤屏障。不带此策略加载后端是有效的,但崩溃可能丢失仍位于已配置批处理窗口内的事件,或尚未完成的写入。第一方持久化应用和运行时显式挂载两个插件;专用部署可以刻意省略或替换策略。
|
|
20
|
+
|
|
21
|
+
策略延迟包装 `llm/stream`,因此下游流只会在活动会话中缓冲的请求事件已持久化后构造。它在预执行策略和防护机制之后包装 `tools/execute`;只有在已记录调用已持久化后,顶层工具正文才会运行。如果取消在 flush 等待期间到达,包装层会返回规范的 `ABORTED_BEFORE_DISPATCH` 结果,不进入工具正文。嵌套工具分派重用外层模型可见调用的检查点。`agent/pre-step` 在派生请求前持久化前一响应/结果批次。
|
|
22
|
+
|
|
23
|
+
在模型和工具边界,检查点被拒绝时会按失败即阻止原则处理:适配器和顶层工具正文都不运行。步骤边界处的检查点被拒绝会在另一个请求开始前使轮次失败。并发工具检查点共享会话存储的串行持久化排空流程,不会产生重复的序列号。
|
|
24
|
+
|
|
25
|
+
## 模型体验
|
|
26
|
+
|
|
27
|
+
### 中断调用
|
|
28
|
+
|
|
29
|
+
#### 模型看到的内容
|
|
30
|
+
|
|
31
|
+
插件不添加提示词或工具 schema。工具检查点后、结果前的硬崩溃会留下持久的未匹配调用;会话恢复会提供模型可见的 `TOOL_OUTCOME_UNKNOWN` 结果,该结果由 `dsh-session` 负责。该消息允许重试只读或幂等工作,并要求对可能有副作用的调用验证状态或请求用户确认。
|
|
32
|
+
|
|
33
|
+
#### Token 影响
|
|
34
|
+
|
|
35
|
+
成功检查点不添加 token,也不改变请求。恢复会添加一条短工具结果消息,以平衡中断的 transcript(文本记录)。
|
|
36
|
+
|
|
37
|
+
#### KV Cache 影响
|
|
38
|
+
|
|
39
|
+
修复结果追加在可重用前缀之后,因此不会使较早的缓存条目失效。
|
|
40
|
+
|
|
41
|
+
## 已知限制与暂缓事项
|
|
42
|
+
|
|
43
|
+
- 该策略以持久方式记录执行意图,而非为通用副作用提供恰好一次保证。当提供方支持时,有副作用的工具应将 `exec.callId` 作为幂等键转发。
|
|
44
|
+
- 流式 `assistant/chunk` 事件没有逐分片检查点。有界后台批次通常会在下一个语义检查点之前将其持久化,但硬崩溃可能丢失当前内存批次或尚未完成的写入。
|
|
45
|
+
- 已持久化的调用没有结果时,无法证明其外部副作用是否完成。因此,恢复会记录未知结果,而不是自动重试。
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { TOOL_ABORTED_BEFORE_DISPATCH } from "@hasna-internal/kai-tools";
|
|
2
|
+
//#region lib/types/index.js
|
|
3
|
+
/**
|
|
4
|
+
* Semantic durability checkpoints for model requests, top-level tool dispatch,
|
|
5
|
+
* and completed agent steps.
|
|
6
|
+
* @module @hasna-internal/kai-session-checkpoint-policy
|
|
7
|
+
*/
|
|
8
|
+
/** Cordis plugin name used by Loader diagnostics. */
|
|
9
|
+
const name = "session-checkpoint-policy";
|
|
10
|
+
/** Services whose request, tool, session, and persistence boundaries this policy joins. */
|
|
11
|
+
const inject = [
|
|
12
|
+
"llm",
|
|
13
|
+
"sessionPersistence",
|
|
14
|
+
"sessions",
|
|
15
|
+
"tools"
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* Delay construction of the downstream model stream until the complete logged
|
|
19
|
+
* request prefix is durable. A checkpoint rejection prevents adapter dispatch.
|
|
20
|
+
*
|
|
21
|
+
* @param ctx - plugin context that owns the session store.
|
|
22
|
+
* @param session - live session named by the model request.
|
|
23
|
+
* @param next - downstream `llm/stream` chain.
|
|
24
|
+
* @returns a stream that checkpoints before requesting its first chunk.
|
|
25
|
+
*/
|
|
26
|
+
function afterCheckpoint(ctx, session, next) {
|
|
27
|
+
return (async function* () {
|
|
28
|
+
await ctx.sessions.flush(session);
|
|
29
|
+
yield* next();
|
|
30
|
+
})();
|
|
31
|
+
}
|
|
32
|
+
/** Materialize the canonical result for a call cancelled before tool dispatch. */
|
|
33
|
+
function abortedBeforeDispatchResult() {
|
|
34
|
+
return {
|
|
35
|
+
content: [{
|
|
36
|
+
type: "text",
|
|
37
|
+
text: "Error: tool call aborted before dispatch"
|
|
38
|
+
}],
|
|
39
|
+
isError: true,
|
|
40
|
+
error: {
|
|
41
|
+
message: "tool call aborted before dispatch",
|
|
42
|
+
info: {
|
|
43
|
+
name: "AbortError",
|
|
44
|
+
code: TOOL_ABORTED_BEFORE_DISPATCH
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Install semantic checkpoint listeners. Loop-built model calls checkpoint the
|
|
51
|
+
* logged request before adapter dispatch; top-level tool calls checkpoint their
|
|
52
|
+
* recorded call before the tool body; the next request boundary checkpoints
|
|
53
|
+
* the preceding response/result batch. Nested tool dispatches reuse the durable outer call.
|
|
54
|
+
*
|
|
55
|
+
* Checkpoint failures are fail-closed at the model and tool side-effect
|
|
56
|
+
* boundaries: the downstream adapter or tool body is not invoked.
|
|
57
|
+
*
|
|
58
|
+
* @param ctx - plugin context that owns the listeners.
|
|
59
|
+
*/
|
|
60
|
+
function apply(ctx) {
|
|
61
|
+
ctx.on("llm/stream", (options, next) => {
|
|
62
|
+
if (options.sessionId === void 0) return next();
|
|
63
|
+
const session = ctx.sessions.get(options.sessionId);
|
|
64
|
+
return session === void 0 ? next() : afterCheckpoint(ctx, session, next);
|
|
65
|
+
});
|
|
66
|
+
ctx.on("tools/execute", async (exec, next) => {
|
|
67
|
+
if (exec.agent === void 0 || exec.parent !== void 0) return next();
|
|
68
|
+
await ctx.sessions.flush(exec.agent.session);
|
|
69
|
+
if (exec.signal.aborted) return abortedBeforeDispatchResult();
|
|
70
|
+
return next();
|
|
71
|
+
});
|
|
72
|
+
ctx.on("agent/pre-step", async ({ agent }, next) => {
|
|
73
|
+
await ctx.sessions.flush(agent.session);
|
|
74
|
+
return next();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { apply, inject, name };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@hasna-internal/kai-session-checkpoint-policy`.
|
|
4
|
+
* @module @hasna-internal/kai-session-checkpoint-policy/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@hasna-internal/kai-session-checkpoint-policy";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "session-checkpoint-policy-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: checkpoint ordering is enforced at the intercepted waterfall and
|
|
13
|
+
* persistence seams; this stateless policy owns no independent mutable relation.
|
|
14
|
+
*/
|
|
15
|
+
const install = () => {};
|
|
16
|
+
/**
|
|
17
|
+
* Register this package's invariant companion.
|
|
18
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
19
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
20
|
+
*/
|
|
21
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
22
|
+
//#endregion
|
|
23
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic durability checkpoints for model requests, top-level tool dispatch,
|
|
3
|
+
* and completed agent steps.
|
|
4
|
+
* @module @hasna-internal/kai-session-checkpoint-policy
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
7
|
+
/** Cordis plugin name used by Loader diagnostics. */
|
|
8
|
+
export declare const name = "session-checkpoint-policy";
|
|
9
|
+
/** Services whose request, tool, session, and persistence boundaries this policy joins. */
|
|
10
|
+
export declare const inject: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Install semantic checkpoint listeners. Loop-built model calls checkpoint the
|
|
13
|
+
* logged request before adapter dispatch; top-level tool calls checkpoint their
|
|
14
|
+
* recorded call before the tool body; the next request boundary checkpoints
|
|
15
|
+
* the preceding response/result batch. Nested tool dispatches reuse the durable outer call.
|
|
16
|
+
*
|
|
17
|
+
* Checkpoint failures are fail-closed at the model and tool side-effect
|
|
18
|
+
* boundaries: the downstream adapter or tool body is not invoked.
|
|
19
|
+
*
|
|
20
|
+
* @param ctx - plugin context that owns the listeners.
|
|
21
|
+
*/
|
|
22
|
+
export declare function apply(ctx: Context): void;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@hasna-internal/kai-session-checkpoint-policy`.
|
|
3
|
+
* @module @hasna-internal/kai-session-checkpoint-policy/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "session-checkpoint-policy-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hasna-internal/kai-session-checkpoint-policy",
|
|
3
|
+
"description": "Semantic session durability checkpoints before model requests and tool side effects",
|
|
4
|
+
"version": "0.1.1-rc.2",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/session/session-checkpoint-policy"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/invariant.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@hasna-internal/kai-agent": "^0.1.1-rc.2",
|
|
36
|
+
"@hasna-internal/kai-invariants": "^0.1.1-rc.2",
|
|
37
|
+
"@hasna-internal/kai-session-persistence": "^0.1.1-rc.2",
|
|
38
|
+
"@hasna-internal/kai-tools": "^0.1.1-rc.2",
|
|
39
|
+
"@hasna-internal/kai-llm": "^0.1.1-rc.2",
|
|
40
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
41
|
+
"@hasna-internal/kai-session": "^0.1.1-rc.2"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.2",
|
|
45
|
+
"@hasna-internal/kai-agent": "^0.1.1-rc.2",
|
|
46
|
+
"@hasna-internal/kai-agent-loop": "^0.1.1-rc.2",
|
|
47
|
+
"@hasna-internal/kai-agent-loop-testkit": "^0.1.1-rc.2",
|
|
48
|
+
"@hasna-internal/kai-invariants": "^0.1.1-rc.2",
|
|
49
|
+
"@hasna-internal/kai-llm": "^0.1.1-rc.2",
|
|
50
|
+
"@hasna-internal/kai-session": "^0.1.1-rc.2",
|
|
51
|
+
"@hasna-internal/kai-session-persistence": "^0.1.1-rc.2",
|
|
52
|
+
"@hasna-internal/kai-session-persistence-jsonl": "^0.1.1-rc.2",
|
|
53
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
54
|
+
"@hasna-internal/kai-tools": "^0.1.1-rc.2",
|
|
55
|
+
"@hasna-internal/kai-system-prompt": "^0.1.1-rc.2"
|
|
56
|
+
}
|
|
57
|
+
}
|