@united-workforce/cli 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 +221 -0
- package/dist/__tests__/adapter-json-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/adapter-json-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/adapter-json-roundtrip.test.js +147 -0
- package/dist/__tests__/adapter-json-roundtrip.test.js.map +1 -0
- package/dist/__tests__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +685 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/current-role.test.d.ts +2 -0
- package/dist/__tests__/current-role.test.d.ts.map +1 -0
- package/dist/__tests__/current-role.test.js +401 -0
- package/dist/__tests__/current-role.test.js.map +1 -0
- package/dist/__tests__/e2e-mock-agent.test.d.ts +2 -0
- package/dist/__tests__/e2e-mock-agent.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-mock-agent.test.js +401 -0
- package/dist/__tests__/e2e-mock-agent.test.js.map +1 -0
- package/dist/__tests__/include-tag.test.d.ts +2 -0
- package/dist/__tests__/include-tag.test.d.ts.map +1 -0
- package/dist/__tests__/include-tag.test.js +69 -0
- package/dist/__tests__/include-tag.test.js.map +1 -0
- package/dist/__tests__/log.test.d.ts +2 -0
- package/dist/__tests__/log.test.d.ts.map +1 -0
- package/dist/__tests__/log.test.js +161 -0
- package/dist/__tests__/log.test.js.map +1 -0
- package/dist/__tests__/moderator-evaluate.test.d.ts +2 -0
- package/dist/__tests__/moderator-evaluate.test.d.ts.map +1 -0
- package/dist/__tests__/moderator-evaluate.test.js +170 -0
- package/dist/__tests__/moderator-evaluate.test.js.map +1 -0
- package/dist/__tests__/preload.d.ts +3 -0
- package/dist/__tests__/preload.d.ts.map +1 -0
- package/dist/__tests__/preload.js +6 -0
- package/dist/__tests__/preload.js.map +1 -0
- package/dist/__tests__/prompt.test.d.ts +2 -0
- package/dist/__tests__/prompt.test.d.ts.map +1 -0
- package/dist/__tests__/prompt.test.js +111 -0
- package/dist/__tests__/prompt.test.js.map +1 -0
- package/dist/__tests__/resolve-head-hash.test.d.ts +2 -0
- package/dist/__tests__/resolve-head-hash.test.d.ts.map +1 -0
- package/dist/__tests__/resolve-head-hash.test.js +66 -0
- package/dist/__tests__/resolve-head-hash.test.js.map +1 -0
- package/dist/__tests__/setup-agent-discovery.test.d.ts +2 -0
- package/dist/__tests__/setup-agent-discovery.test.d.ts.map +1 -0
- package/dist/__tests__/setup-agent-discovery.test.js +119 -0
- package/dist/__tests__/setup-agent-discovery.test.js.map +1 -0
- package/dist/__tests__/setup-complexity.test.d.ts +2 -0
- package/dist/__tests__/setup-complexity.test.d.ts.map +1 -0
- package/dist/__tests__/setup-complexity.test.js +314 -0
- package/dist/__tests__/setup-complexity.test.js.map +1 -0
- package/dist/__tests__/setup-validate.test.d.ts +2 -0
- package/dist/__tests__/setup-validate.test.d.ts.map +1 -0
- package/dist/__tests__/setup-validate.test.js +108 -0
- package/dist/__tests__/setup-validate.test.js.map +1 -0
- package/dist/__tests__/solve-issue-tea-worktree.test.d.ts +2 -0
- package/dist/__tests__/solve-issue-tea-worktree.test.d.ts.map +1 -0
- package/dist/__tests__/solve-issue-tea-worktree.test.js +107 -0
- package/dist/__tests__/solve-issue-tea-worktree.test.js.map +1 -0
- package/dist/__tests__/spawn-agent-json.test.d.ts +2 -0
- package/dist/__tests__/spawn-agent-json.test.d.ts.map +1 -0
- package/dist/__tests__/spawn-agent-json.test.js +79 -0
- package/dist/__tests__/spawn-agent-json.test.js.map +1 -0
- package/dist/__tests__/step-read.test.d.ts +2 -0
- package/dist/__tests__/step-read.test.d.ts.map +1 -0
- package/dist/__tests__/step-read.test.js +561 -0
- package/dist/__tests__/step-read.test.js.map +1 -0
- package/dist/__tests__/step-show-json.test.d.ts +2 -0
- package/dist/__tests__/step-show-json.test.d.ts.map +1 -0
- package/dist/__tests__/step-show-json.test.js +311 -0
- package/dist/__tests__/step-show-json.test.js.map +1 -0
- package/dist/__tests__/step-timing.test.d.ts +2 -0
- package/dist/__tests__/step-timing.test.d.ts.map +1 -0
- package/dist/__tests__/step-timing.test.js +345 -0
- package/dist/__tests__/step-timing.test.js.map +1 -0
- package/dist/__tests__/store-global-cas.test.d.ts +2 -0
- package/dist/__tests__/store-global-cas.test.d.ts.map +1 -0
- package/dist/__tests__/store-global-cas.test.js +235 -0
- package/dist/__tests__/store-global-cas.test.js.map +1 -0
- package/dist/__tests__/store-storage-root.test.d.ts +2 -0
- package/dist/__tests__/store-storage-root.test.d.ts.map +1 -0
- package/dist/__tests__/store-storage-root.test.js +43 -0
- package/dist/__tests__/store-storage-root.test.js.map +1 -0
- package/dist/__tests__/store-unified-threads.test.d.ts +2 -0
- package/dist/__tests__/store-unified-threads.test.d.ts.map +1 -0
- package/dist/__tests__/store-unified-threads.test.js +189 -0
- package/dist/__tests__/store-unified-threads.test.js.map +1 -0
- package/dist/__tests__/thread-cancel-status.test.d.ts +2 -0
- package/dist/__tests__/thread-cancel-status.test.d.ts.map +1 -0
- package/dist/__tests__/thread-cancel-status.test.js +111 -0
- package/dist/__tests__/thread-cancel-status.test.js.map +1 -0
- package/dist/__tests__/thread-list-filters.test.d.ts +2 -0
- package/dist/__tests__/thread-list-filters.test.d.ts.map +1 -0
- package/dist/__tests__/thread-list-filters.test.js +442 -0
- package/dist/__tests__/thread-list-filters.test.js.map +1 -0
- package/dist/__tests__/thread-location.test.d.ts +2 -0
- package/dist/__tests__/thread-location.test.d.ts.map +1 -0
- package/dist/__tests__/thread-location.test.js +159 -0
- package/dist/__tests__/thread-location.test.js.map +1 -0
- package/dist/__tests__/thread-read-quota.test.d.ts +2 -0
- package/dist/__tests__/thread-read-quota.test.d.ts.map +1 -0
- package/dist/__tests__/thread-read-quota.test.js +546 -0
- package/dist/__tests__/thread-read-quota.test.js.map +1 -0
- package/dist/__tests__/thread-read-xml-tags.test.d.ts +2 -0
- package/dist/__tests__/thread-read-xml-tags.test.d.ts.map +1 -0
- package/dist/__tests__/thread-read-xml-tags.test.js +610 -0
- package/dist/__tests__/thread-read-xml-tags.test.js.map +1 -0
- package/dist/__tests__/thread-resume.test.d.ts +2 -0
- package/dist/__tests__/thread-resume.test.d.ts.map +1 -0
- package/dist/__tests__/thread-resume.test.js +592 -0
- package/dist/__tests__/thread-resume.test.js.map +1 -0
- package/dist/__tests__/thread-show-status.test.d.ts +2 -0
- package/dist/__tests__/thread-show-status.test.d.ts.map +1 -0
- package/dist/__tests__/thread-show-status.test.js +267 -0
- package/dist/__tests__/thread-show-status.test.js.map +1 -0
- package/dist/__tests__/thread-start-cwd-cli.test.d.ts +2 -0
- package/dist/__tests__/thread-start-cwd-cli.test.d.ts.map +1 -0
- package/dist/__tests__/thread-start-cwd-cli.test.js +130 -0
- package/dist/__tests__/thread-start-cwd-cli.test.js.map +1 -0
- package/dist/__tests__/thread-step-count.test.d.ts +2 -0
- package/dist/__tests__/thread-step-count.test.d.ts.map +1 -0
- package/dist/__tests__/thread-step-count.test.js +55 -0
- package/dist/__tests__/thread-step-count.test.js.map +1 -0
- package/dist/__tests__/thread-suspend-step.test.d.ts +2 -0
- package/dist/__tests__/thread-suspend-step.test.d.ts.map +1 -0
- package/dist/__tests__/thread-suspend-step.test.js +155 -0
- package/dist/__tests__/thread-suspend-step.test.js.map +1 -0
- package/dist/__tests__/thread-suspended-display.test.d.ts +2 -0
- package/dist/__tests__/thread-suspended-display.test.d.ts.map +1 -0
- package/dist/__tests__/thread-suspended-display.test.js +247 -0
- package/dist/__tests__/thread-suspended-display.test.js.map +1 -0
- package/dist/__tests__/thread-test-helpers.d.ts +4 -0
- package/dist/__tests__/thread-test-helpers.d.ts.map +1 -0
- package/dist/__tests__/thread-test-helpers.js +23 -0
- package/dist/__tests__/thread-test-helpers.js.map +1 -0
- package/dist/__tests__/thread.test.d.ts +2 -0
- package/dist/__tests__/thread.test.d.ts.map +1 -0
- package/dist/__tests__/thread.test.js +883 -0
- package/dist/__tests__/thread.test.js.map +1 -0
- package/dist/__tests__/validate-semantic.test.d.ts +2 -0
- package/dist/__tests__/validate-semantic.test.d.ts.map +1 -0
- package/dist/__tests__/validate-semantic.test.js +408 -0
- package/dist/__tests__/validate-semantic.test.js.map +1 -0
- package/dist/__tests__/workflow-resolution.test.d.ts +2 -0
- package/dist/__tests__/workflow-resolution.test.d.ts.map +1 -0
- package/dist/__tests__/workflow-resolution.test.js +308 -0
- package/dist/__tests__/workflow-resolution.test.js.map +1 -0
- package/dist/background/background.d.ts +38 -0
- package/dist/background/background.d.ts.map +1 -0
- package/dist/background/background.js +123 -0
- package/dist/background/background.js.map +1 -0
- package/dist/background/index.d.ts +3 -0
- package/dist/background/index.d.ts.map +1 -0
- package/dist/background/index.js +2 -0
- package/dist/background/index.js.map +1 -0
- package/dist/background/types.d.ts +9 -0
- package/dist/background/types.d.ts.map +1 -0
- package/dist/background/types.js +2 -0
- package/dist/background/types.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +535 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.d.ts +41 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +252 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/log.d.ts +26 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +79 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/prompt.d.ts +6 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/prompt.js +67 -0
- package/dist/commands/prompt.js.map +1 -0
- package/dist/commands/setup.d.ts +73 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +522 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/shared.d.ts +31 -0
- package/dist/commands/shared.d.ts.map +1 -0
- package/dist/commands/shared.js +154 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/step.d.ts +18 -0
- package/dist/commands/step.d.ts.map +1 -0
- package/dist/commands/step.js +257 -0
- package/dist/commands/step.js.map +1 -0
- package/dist/commands/thread-time-parser.d.ts +6 -0
- package/dist/commands/thread-time-parser.d.ts.map +1 -0
- package/dist/commands/thread-time-parser.js +22 -0
- package/dist/commands/thread-time-parser.js.map +1 -0
- package/dist/commands/thread.d.ts +38 -0
- package/dist/commands/thread.d.ts.map +1 -0
- package/dist/commands/thread.js +1087 -0
- package/dist/commands/thread.js.map +1 -0
- package/dist/commands/workflow.d.ts +24 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +138 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/format.d.ts +3 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +10 -0
- package/dist/format.js.map +1 -0
- package/dist/include.d.ts +12 -0
- package/dist/include.d.ts.map +1 -0
- package/dist/include.js +35 -0
- package/dist/include.js.map +1 -0
- package/dist/moderator/__tests__/evaluate.test.d.ts +2 -0
- package/dist/moderator/__tests__/evaluate.test.d.ts.map +1 -0
- package/dist/moderator/__tests__/evaluate.test.js +167 -0
- package/dist/moderator/__tests__/evaluate.test.js.map +1 -0
- package/dist/moderator/evaluate.d.ts +6 -0
- package/dist/moderator/evaluate.d.ts.map +1 -0
- package/dist/moderator/evaluate.js +65 -0
- package/dist/moderator/evaluate.js.map +1 -0
- package/dist/moderator/index.d.ts +4 -0
- package/dist/moderator/index.d.ts.map +1 -0
- package/dist/moderator/index.js +3 -0
- package/dist/moderator/index.js.map +1 -0
- package/dist/moderator/types.d.ts +25 -0
- package/dist/moderator/types.d.ts.map +1 -0
- package/dist/moderator/types.js +4 -0
- package/dist/moderator/types.js.map +1 -0
- package/dist/schemas.d.ts +16 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +17 -0
- package/dist/schemas.js.map +1 -0
- package/dist/store.d.ts +77 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +392 -0
- package/dist/store.js.map +1 -0
- package/dist/validate-semantic.d.ts +7 -0
- package/dist/validate-semantic.d.ts.map +1 -0
- package/dist/validate-semantic.js +263 -0
- package/dist/validate-semantic.js.map +1 -0
- package/dist/validate.d.ts +16 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +115 -0
- package/dist/validate.js.map +1 -0
- package/package.json +44 -0
- package/src/__tests__/adapter-json-roundtrip.test.ts +181 -0
- package/src/__tests__/config.test.ts +740 -0
- package/src/__tests__/current-role.test.ts +438 -0
- package/src/__tests__/e2e-mock-agent.test.ts +498 -0
- package/src/__tests__/fixtures/e2e-completed-resume.mock.yaml +15 -0
- package/src/__tests__/fixtures/e2e-count.mock.yaml +19 -0
- package/src/__tests__/fixtures/e2e-count.workflow.yaml +45 -0
- package/src/__tests__/fixtures/e2e-linear.mock.yaml +13 -0
- package/src/__tests__/fixtures/e2e-linear.workflow.yaml +32 -0
- package/src/__tests__/fixtures/e2e-loop.mock.yaml +25 -0
- package/src/__tests__/fixtures/e2e-loop.workflow.yaml +36 -0
- package/src/__tests__/fixtures/e2e-mismatch.mock.yaml +16 -0
- package/src/__tests__/fixtures/e2e-mustache.mock.yaml +15 -0
- package/src/__tests__/fixtures/e2e-mustache.workflow.yaml +34 -0
- package/src/__tests__/fixtures/e2e-suspend.mock.yaml +14 -0
- package/src/__tests__/fixtures/e2e-suspend.workflow.yaml +24 -0
- package/src/__tests__/include-tag.test.ts +84 -0
- package/src/__tests__/log.test.ts +181 -0
- package/src/__tests__/moderator-evaluate.test.ts +186 -0
- package/src/__tests__/preload.ts +7 -0
- package/src/__tests__/prompt.test.ts +129 -0
- package/src/__tests__/resolve-head-hash.test.ts +86 -0
- package/src/__tests__/setup-agent-discovery.test.ts +167 -0
- package/src/__tests__/setup-complexity.test.ts +381 -0
- package/src/__tests__/setup-validate.test.ts +148 -0
- package/src/__tests__/solve-issue-tea-worktree.test.ts +144 -0
- package/src/__tests__/spawn-agent-json.test.ts +100 -0
- package/src/__tests__/step-read.test.ts +632 -0
- package/src/__tests__/step-show-json.test.ts +373 -0
- package/src/__tests__/step-timing.test.ts +392 -0
- package/src/__tests__/store-global-cas.test.ts +308 -0
- package/src/__tests__/store-storage-root.test.ts +49 -0
- package/src/__tests__/store-unified-threads.test.ts +235 -0
- package/src/__tests__/thread-cancel-status.test.ts +138 -0
- package/src/__tests__/thread-list-filters.test.ts +572 -0
- package/src/__tests__/thread-location.test.ts +186 -0
- package/src/__tests__/thread-read-quota.test.ts +613 -0
- package/src/__tests__/thread-read-xml-tags.test.ts +717 -0
- package/src/__tests__/thread-resume.test.ts +710 -0
- package/src/__tests__/thread-show-status.test.ts +317 -0
- package/src/__tests__/thread-start-cwd-cli.test.ts +164 -0
- package/src/__tests__/thread-step-count.test.ts +70 -0
- package/src/__tests__/thread-suspend-step.test.ts +181 -0
- package/src/__tests__/thread-suspended-display.test.ts +287 -0
- package/src/__tests__/thread-test-helpers.ts +37 -0
- package/src/__tests__/thread.test.ts +1025 -0
- package/src/__tests__/validate-semantic.test.ts +474 -0
- package/src/__tests__/workflow-resolution.test.ts +421 -0
- package/src/background/background.ts +147 -0
- package/src/background/index.ts +11 -0
- package/src/background/types.ts +9 -0
- package/src/cli.ts +692 -0
- package/src/commands/config.ts +304 -0
- package/src/commands/log.ts +116 -0
- package/src/commands/prompt.ts +81 -0
- package/src/commands/setup.ts +603 -0
- package/src/commands/shared.ts +227 -0
- package/src/commands/step.ts +343 -0
- package/src/commands/thread-time-parser.ts +23 -0
- package/src/commands/thread.ts +1575 -0
- package/src/commands/workflow.ts +213 -0
- package/src/format.ts +12 -0
- package/src/include.ts +37 -0
- package/src/moderator/__tests__/evaluate.test.ts +199 -0
- package/src/moderator/evaluate.ts +80 -0
- package/src/moderator/index.ts +7 -0
- package/src/moderator/types.ts +24 -0
- package/src/schemas.ts +26 -0
- package/src/store.ts +479 -0
- package/src/validate-semantic.ts +304 -0
- package/src/validate.ts +137 -0
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { bootstrap, putSchema } from "@ocas/core";
|
|
5
|
+
import { openStore } from "@ocas/fs";
|
|
6
|
+
import type { CasRef, ThreadId } from "@united-workforce/protocol";
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
8
|
+
import { cmdThreadRead } from "../commands/thread.js";
|
|
9
|
+
import { registerUwfSchemas } from "../schemas.js";
|
|
10
|
+
import { seedThreads } from "./thread-test-helpers.js";
|
|
11
|
+
|
|
12
|
+
// ── schemas used in tests ────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
const TURN_SCHEMA = {
|
|
15
|
+
title: "hermes-turn",
|
|
16
|
+
type: "object" as const,
|
|
17
|
+
required: ["index", "role", "content"],
|
|
18
|
+
properties: {
|
|
19
|
+
index: { type: "integer" as const },
|
|
20
|
+
role: { type: "string" as const },
|
|
21
|
+
content: { type: "string" as const },
|
|
22
|
+
toolCalls: {
|
|
23
|
+
anyOf: [
|
|
24
|
+
{ type: "array" as const, items: { type: "object" as const } },
|
|
25
|
+
{ type: "null" as const },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
reasoning: { anyOf: [{ type: "string" as const }, { type: "null" as const }] },
|
|
29
|
+
},
|
|
30
|
+
additionalProperties: false,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const DETAIL_SCHEMA = {
|
|
34
|
+
title: "hermes-detail",
|
|
35
|
+
type: "object" as const,
|
|
36
|
+
required: ["sessionId", "model", "duration", "turnCount", "turns"],
|
|
37
|
+
properties: {
|
|
38
|
+
sessionId: { type: "string" as const },
|
|
39
|
+
model: { type: "string" as const },
|
|
40
|
+
duration: { type: "integer" as const },
|
|
41
|
+
turnCount: { type: "integer" as const },
|
|
42
|
+
turns: {
|
|
43
|
+
type: "array" as const,
|
|
44
|
+
items: { type: "string" as const, format: "ocas_ref" },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
additionalProperties: false,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
async function registerDetailSchemas(store: Awaited<ReturnType<typeof openStore>>) {
|
|
53
|
+
await bootstrap(store);
|
|
54
|
+
const [turn, detail] = await Promise.all([
|
|
55
|
+
putSchema(store, TURN_SCHEMA),
|
|
56
|
+
putSchema(store, DETAIL_SCHEMA),
|
|
57
|
+
]);
|
|
58
|
+
return { turn, detail };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function generateContent(size: number, prefix = "Content"): string {
|
|
62
|
+
const base = `${prefix} `;
|
|
63
|
+
const repeat = Math.ceil(size / base.length);
|
|
64
|
+
return base.repeat(repeat).slice(0, size);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── fixture ───────────────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
let tmpDir: string;
|
|
70
|
+
let originalEnv: string | undefined;
|
|
71
|
+
|
|
72
|
+
beforeEach(async () => {
|
|
73
|
+
tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-quota-test-"));
|
|
74
|
+
originalEnv = process.env.OCAS_HOME;
|
|
75
|
+
process.env.OCAS_HOME = join(tmpDir, "cas");
|
|
76
|
+
await mkdir(process.env.OCAS_HOME, { recursive: true });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
afterEach(async () => {
|
|
80
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
81
|
+
if (originalEnv === undefined) {
|
|
82
|
+
delete process.env.OCAS_HOME;
|
|
83
|
+
} else {
|
|
84
|
+
process.env.OCAS_HOME = originalEnv;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// ── thread read quota enforcement ─────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
describe("thread read --quota flag", () => {
|
|
91
|
+
test("test 1: basic quota enforcement with 3 steps", async () => {
|
|
92
|
+
const casDir = join(tmpDir, "cas");
|
|
93
|
+
await mkdir(casDir, { recursive: true });
|
|
94
|
+
const store = await openStore(casDir);
|
|
95
|
+
const schemas = await registerUwfSchemas(store);
|
|
96
|
+
const detailSchemas = await registerDetailSchemas(store);
|
|
97
|
+
|
|
98
|
+
const workflowHash = await store.cas.put(schemas.workflow, {
|
|
99
|
+
name: "test-wf",
|
|
100
|
+
description: "desc",
|
|
101
|
+
roles: {
|
|
102
|
+
worker: {
|
|
103
|
+
description: "Worker",
|
|
104
|
+
goal: "You are a worker agent.",
|
|
105
|
+
capabilities: [],
|
|
106
|
+
procedure: "Do the work.",
|
|
107
|
+
output: "Summarize the work.",
|
|
108
|
+
meta: "placeholder00" as CasRef,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
conditions: {},
|
|
112
|
+
graph: {},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const startHash = await store.cas.put(schemas.startNode, {
|
|
116
|
+
workflow: workflowHash,
|
|
117
|
+
prompt: "Test task",
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const outputHash = await store.cas.put(schemas.workflow, {
|
|
121
|
+
name: "out",
|
|
122
|
+
description: "",
|
|
123
|
+
roles: {},
|
|
124
|
+
conditions: {},
|
|
125
|
+
graph: {},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Create 3 steps with ~500 chars each
|
|
129
|
+
const steps: CasRef[] = [];
|
|
130
|
+
for (let i = 1; i <= 3; i++) {
|
|
131
|
+
const content = generateContent(500, `Step${i}`);
|
|
132
|
+
const turnHash = await store.cas.put(detailSchemas.turn, {
|
|
133
|
+
index: 0,
|
|
134
|
+
role: "assistant",
|
|
135
|
+
content,
|
|
136
|
+
toolCalls: null,
|
|
137
|
+
reasoning: null,
|
|
138
|
+
});
|
|
139
|
+
const detailHash = await store.cas.put(detailSchemas.detail, {
|
|
140
|
+
sessionId: `session-${i}`,
|
|
141
|
+
model: "test-model",
|
|
142
|
+
duration: 1000,
|
|
143
|
+
turnCount: 1,
|
|
144
|
+
turns: [turnHash],
|
|
145
|
+
});
|
|
146
|
+
const stepHash = await store.cas.put(schemas.stepNode, {
|
|
147
|
+
start: startHash,
|
|
148
|
+
prev: steps[i - 2] ?? null,
|
|
149
|
+
role: "worker",
|
|
150
|
+
output: outputHash,
|
|
151
|
+
detail: detailHash,
|
|
152
|
+
agent: "uwf-test",
|
|
153
|
+
startedAtMs: 1000000000000,
|
|
154
|
+
completedAtMs: 1000000005000,
|
|
155
|
+
assembledPrompt: null,
|
|
156
|
+
});
|
|
157
|
+
steps.push(stepHash);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const threadId = "01HX2Q3R4S5T6V7W8X9YZ0" as ThreadId;
|
|
161
|
+
await seedThreads(tmpDir, { [threadId]: steps[2] as CasRef });
|
|
162
|
+
|
|
163
|
+
// Set quota to 800 chars - should only fit most recent steps
|
|
164
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, 800, null, false);
|
|
165
|
+
|
|
166
|
+
// Quota must be reasonably enforced (allow ~200 char tolerance for skip hint)
|
|
167
|
+
expect(markdown.length).toBeLessThanOrEqual(1000);
|
|
168
|
+
|
|
169
|
+
// Should contain skip hint since not all steps fit
|
|
170
|
+
expect(markdown).toMatch(/earlier step/);
|
|
171
|
+
|
|
172
|
+
// Most recent step should be included
|
|
173
|
+
expect(markdown).toMatch(/Step3/);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("test 2: quota check order - verifies bug is fixed", async () => {
|
|
177
|
+
const casDir = join(tmpDir, "cas");
|
|
178
|
+
await mkdir(casDir, { recursive: true });
|
|
179
|
+
const store = await openStore(casDir);
|
|
180
|
+
const schemas = await registerUwfSchemas(store);
|
|
181
|
+
const detailSchemas = await registerDetailSchemas(store);
|
|
182
|
+
|
|
183
|
+
const workflowHash = await store.cas.put(schemas.workflow, {
|
|
184
|
+
name: "test-wf",
|
|
185
|
+
description: "desc",
|
|
186
|
+
roles: {
|
|
187
|
+
worker: {
|
|
188
|
+
description: "Worker",
|
|
189
|
+
goal: "You are a worker agent.",
|
|
190
|
+
capabilities: [],
|
|
191
|
+
procedure: "Do the work.",
|
|
192
|
+
output: "Summarize the work.",
|
|
193
|
+
meta: "placeholder00" as CasRef,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
conditions: {},
|
|
197
|
+
graph: {},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const startHash = await store.cas.put(schemas.startNode, {
|
|
201
|
+
workflow: workflowHash,
|
|
202
|
+
prompt: "Test task",
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const outputHash = await store.cas.put(schemas.workflow, {
|
|
206
|
+
name: "out",
|
|
207
|
+
description: "",
|
|
208
|
+
roles: {},
|
|
209
|
+
conditions: {},
|
|
210
|
+
graph: {},
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Create 2 steps: first=300 chars, second=600 chars
|
|
214
|
+
const step1Content = generateContent(300, "First");
|
|
215
|
+
const step1TurnHash = await store.cas.put(detailSchemas.turn, {
|
|
216
|
+
index: 0,
|
|
217
|
+
role: "assistant",
|
|
218
|
+
content: step1Content,
|
|
219
|
+
toolCalls: null,
|
|
220
|
+
reasoning: null,
|
|
221
|
+
});
|
|
222
|
+
const step1DetailHash = await store.cas.put(detailSchemas.detail, {
|
|
223
|
+
sessionId: "session-1",
|
|
224
|
+
model: "test-model",
|
|
225
|
+
duration: 1000,
|
|
226
|
+
turnCount: 1,
|
|
227
|
+
turns: [step1TurnHash],
|
|
228
|
+
});
|
|
229
|
+
const step1Hash = await store.cas.put(schemas.stepNode, {
|
|
230
|
+
start: startHash,
|
|
231
|
+
prev: null,
|
|
232
|
+
role: "worker",
|
|
233
|
+
output: outputHash,
|
|
234
|
+
detail: step1DetailHash,
|
|
235
|
+
agent: "uwf-test",
|
|
236
|
+
startedAtMs: 1000000000000,
|
|
237
|
+
completedAtMs: 1000000005000,
|
|
238
|
+
assembledPrompt: null,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const step2Content = generateContent(600, "Second");
|
|
242
|
+
const step2TurnHash = await store.cas.put(detailSchemas.turn, {
|
|
243
|
+
index: 0,
|
|
244
|
+
role: "assistant",
|
|
245
|
+
content: step2Content,
|
|
246
|
+
toolCalls: null,
|
|
247
|
+
reasoning: null,
|
|
248
|
+
});
|
|
249
|
+
const step2DetailHash = await store.cas.put(detailSchemas.detail, {
|
|
250
|
+
sessionId: "session-2",
|
|
251
|
+
model: "test-model",
|
|
252
|
+
duration: 1000,
|
|
253
|
+
turnCount: 1,
|
|
254
|
+
turns: [step2TurnHash],
|
|
255
|
+
});
|
|
256
|
+
const step2Hash = await store.cas.put(schemas.stepNode, {
|
|
257
|
+
start: startHash,
|
|
258
|
+
prev: step1Hash,
|
|
259
|
+
role: "worker",
|
|
260
|
+
output: outputHash,
|
|
261
|
+
detail: step2DetailHash,
|
|
262
|
+
agent: "uwf-test",
|
|
263
|
+
startedAtMs: 1000000000000,
|
|
264
|
+
completedAtMs: 1000000005000,
|
|
265
|
+
assembledPrompt: null,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const threadId = "01HX2Q3R4S5T6V7W8X9YZ1" as ThreadId;
|
|
269
|
+
await seedThreads(tmpDir, { [threadId]: step2Hash });
|
|
270
|
+
|
|
271
|
+
// Set quota to 500 chars
|
|
272
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, 500, null, false);
|
|
273
|
+
|
|
274
|
+
// Bug fix verification: output must be limited (allow ~200 char tolerance)
|
|
275
|
+
expect(markdown.length).toBeLessThanOrEqual(1100);
|
|
276
|
+
|
|
277
|
+
// Should contain "Second" (most recent step)
|
|
278
|
+
expect(markdown).toMatch(/Second/);
|
|
279
|
+
|
|
280
|
+
// Should skip first step
|
|
281
|
+
expect(markdown).toMatch(/earlier step/);
|
|
282
|
+
|
|
283
|
+
// Verify improvement: before fix would be ~1264, now should be much closer to 500
|
|
284
|
+
expect(markdown.length).toBeLessThan(1200);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test("test 3: quota with --start section", async () => {
|
|
288
|
+
const casDir = join(tmpDir, "cas");
|
|
289
|
+
await mkdir(casDir, { recursive: true });
|
|
290
|
+
const store = await openStore(casDir);
|
|
291
|
+
const schemas = await registerUwfSchemas(store);
|
|
292
|
+
const detailSchemas = await registerDetailSchemas(store);
|
|
293
|
+
|
|
294
|
+
const workflowHash = await store.cas.put(schemas.workflow, {
|
|
295
|
+
name: "test-wf",
|
|
296
|
+
description: "desc",
|
|
297
|
+
roles: {
|
|
298
|
+
worker: {
|
|
299
|
+
description: "Worker",
|
|
300
|
+
goal: "You are a worker agent.",
|
|
301
|
+
capabilities: [],
|
|
302
|
+
procedure: "Do the work.",
|
|
303
|
+
output: "Summarize the work.",
|
|
304
|
+
meta: "placeholder00" as CasRef,
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
conditions: {},
|
|
308
|
+
graph: {},
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const startHash = await store.cas.put(schemas.startNode, {
|
|
312
|
+
workflow: workflowHash,
|
|
313
|
+
prompt: "Test task with a moderately long prompt to test quota accounting",
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const outputHash = await store.cas.put(schemas.workflow, {
|
|
317
|
+
name: "out",
|
|
318
|
+
description: "",
|
|
319
|
+
roles: {},
|
|
320
|
+
conditions: {},
|
|
321
|
+
graph: {},
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Create 2 steps
|
|
325
|
+
const steps: CasRef[] = [];
|
|
326
|
+
for (let i = 1; i <= 2; i++) {
|
|
327
|
+
const content = generateContent(400, `Step${i}`);
|
|
328
|
+
const turnHash = await store.cas.put(detailSchemas.turn, {
|
|
329
|
+
index: 0,
|
|
330
|
+
role: "assistant",
|
|
331
|
+
content,
|
|
332
|
+
toolCalls: null,
|
|
333
|
+
reasoning: null,
|
|
334
|
+
});
|
|
335
|
+
const detailHash = await store.cas.put(detailSchemas.detail, {
|
|
336
|
+
sessionId: `session-${i}`,
|
|
337
|
+
model: "test-model",
|
|
338
|
+
duration: 1000,
|
|
339
|
+
turnCount: 1,
|
|
340
|
+
turns: [turnHash],
|
|
341
|
+
});
|
|
342
|
+
const stepHash = await store.cas.put(schemas.stepNode, {
|
|
343
|
+
start: startHash,
|
|
344
|
+
prev: steps[i - 2] ?? null,
|
|
345
|
+
role: "worker",
|
|
346
|
+
output: outputHash,
|
|
347
|
+
detail: detailHash,
|
|
348
|
+
agent: "uwf-test",
|
|
349
|
+
startedAtMs: 1000000000000,
|
|
350
|
+
completedAtMs: 1000000005000,
|
|
351
|
+
assembledPrompt: null,
|
|
352
|
+
});
|
|
353
|
+
steps.push(stepHash);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const threadId = "01HX2Q3R4S5T6V7W8X9YZ2" as ThreadId;
|
|
357
|
+
await seedThreads(tmpDir, { [threadId]: steps[1] as CasRef });
|
|
358
|
+
|
|
359
|
+
// Set tight quota with --start flag
|
|
360
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, 600, null, true);
|
|
361
|
+
|
|
362
|
+
// Quota must be reasonably enforced (allow ~260 char tolerance for structure)
|
|
363
|
+
expect(markdown.length).toBeLessThanOrEqual(860);
|
|
364
|
+
|
|
365
|
+
// Should contain thread header
|
|
366
|
+
expect(markdown).toMatch(/# Thread/);
|
|
367
|
+
expect(markdown).toMatch(/test-wf/);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test("test 5a: quota edge case - minimal quota", async () => {
|
|
371
|
+
const casDir = join(tmpDir, "cas");
|
|
372
|
+
await mkdir(casDir, { recursive: true });
|
|
373
|
+
const store = await openStore(casDir);
|
|
374
|
+
const schemas = await registerUwfSchemas(store);
|
|
375
|
+
const detailSchemas = await registerDetailSchemas(store);
|
|
376
|
+
|
|
377
|
+
const workflowHash = await store.cas.put(schemas.workflow, {
|
|
378
|
+
name: "test-wf",
|
|
379
|
+
description: "desc",
|
|
380
|
+
roles: {
|
|
381
|
+
worker: {
|
|
382
|
+
description: "Worker",
|
|
383
|
+
goal: "You are a worker agent.",
|
|
384
|
+
capabilities: [],
|
|
385
|
+
procedure: "Do the work.",
|
|
386
|
+
output: "Summarize the work.",
|
|
387
|
+
meta: "placeholder00" as CasRef,
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
conditions: {},
|
|
391
|
+
graph: {},
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
const startHash = await store.cas.put(schemas.startNode, {
|
|
395
|
+
workflow: workflowHash,
|
|
396
|
+
prompt: "Test task",
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
const outputHash = await store.cas.put(schemas.workflow, {
|
|
400
|
+
name: "out",
|
|
401
|
+
description: "",
|
|
402
|
+
roles: {},
|
|
403
|
+
conditions: {},
|
|
404
|
+
graph: {},
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
const content = generateContent(500, "Test");
|
|
408
|
+
const turnHash = await store.cas.put(detailSchemas.turn, {
|
|
409
|
+
index: 0,
|
|
410
|
+
role: "assistant",
|
|
411
|
+
content,
|
|
412
|
+
toolCalls: null,
|
|
413
|
+
reasoning: null,
|
|
414
|
+
});
|
|
415
|
+
const detailHash = await store.cas.put(detailSchemas.detail, {
|
|
416
|
+
sessionId: "session-1",
|
|
417
|
+
model: "test-model",
|
|
418
|
+
duration: 1000,
|
|
419
|
+
turnCount: 1,
|
|
420
|
+
turns: [turnHash],
|
|
421
|
+
});
|
|
422
|
+
const stepHash = await store.cas.put(schemas.stepNode, {
|
|
423
|
+
start: startHash,
|
|
424
|
+
prev: null,
|
|
425
|
+
role: "worker",
|
|
426
|
+
output: outputHash,
|
|
427
|
+
detail: detailHash,
|
|
428
|
+
agent: "uwf-test",
|
|
429
|
+
startedAtMs: 1000000000000,
|
|
430
|
+
completedAtMs: 1000000005000,
|
|
431
|
+
assembledPrompt: null,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
const threadId = "01HX2Q3R4S5T6V7W8X9YZ4" as ThreadId;
|
|
435
|
+
await seedThreads(tmpDir, { [threadId]: stepHash });
|
|
436
|
+
|
|
437
|
+
// Minimal quota
|
|
438
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, 1, null, false);
|
|
439
|
+
|
|
440
|
+
// Should handle gracefully - always shows at least one step
|
|
441
|
+
expect(markdown.length).toBeGreaterThan(1);
|
|
442
|
+
expect(markdown).toMatch(/Test/);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test("test 5b: quota edge case - very large quota", async () => {
|
|
446
|
+
const casDir = join(tmpDir, "cas");
|
|
447
|
+
await mkdir(casDir, { recursive: true });
|
|
448
|
+
const store = await openStore(casDir);
|
|
449
|
+
const schemas = await registerUwfSchemas(store);
|
|
450
|
+
const detailSchemas = await registerDetailSchemas(store);
|
|
451
|
+
|
|
452
|
+
const workflowHash = await store.cas.put(schemas.workflow, {
|
|
453
|
+
name: "test-wf",
|
|
454
|
+
description: "desc",
|
|
455
|
+
roles: {
|
|
456
|
+
worker: {
|
|
457
|
+
description: "Worker",
|
|
458
|
+
goal: "You are a worker agent.",
|
|
459
|
+
capabilities: [],
|
|
460
|
+
procedure: "Do the work.",
|
|
461
|
+
output: "Summarize the work.",
|
|
462
|
+
meta: "placeholder00" as CasRef,
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
conditions: {},
|
|
466
|
+
graph: {},
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
const startHash = await store.cas.put(schemas.startNode, {
|
|
470
|
+
workflow: workflowHash,
|
|
471
|
+
prompt: "Test task",
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
const outputHash = await store.cas.put(schemas.workflow, {
|
|
475
|
+
name: "out",
|
|
476
|
+
description: "",
|
|
477
|
+
roles: {},
|
|
478
|
+
conditions: {},
|
|
479
|
+
graph: {},
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Create 3 steps
|
|
483
|
+
const steps: CasRef[] = [];
|
|
484
|
+
for (let i = 1; i <= 3; i++) {
|
|
485
|
+
const content = generateContent(300, `Step${i}`);
|
|
486
|
+
const turnHash = await store.cas.put(detailSchemas.turn, {
|
|
487
|
+
index: 0,
|
|
488
|
+
role: "assistant",
|
|
489
|
+
content,
|
|
490
|
+
toolCalls: null,
|
|
491
|
+
reasoning: null,
|
|
492
|
+
});
|
|
493
|
+
const detailHash = await store.cas.put(detailSchemas.detail, {
|
|
494
|
+
sessionId: `session-${i}`,
|
|
495
|
+
model: "test-model",
|
|
496
|
+
duration: 1000,
|
|
497
|
+
turnCount: 1,
|
|
498
|
+
turns: [turnHash],
|
|
499
|
+
});
|
|
500
|
+
const stepHash = await store.cas.put(schemas.stepNode, {
|
|
501
|
+
start: startHash,
|
|
502
|
+
prev: steps[i - 2] ?? null,
|
|
503
|
+
role: "worker",
|
|
504
|
+
output: outputHash,
|
|
505
|
+
detail: detailHash,
|
|
506
|
+
agent: "uwf-test",
|
|
507
|
+
startedAtMs: 1000000000000,
|
|
508
|
+
completedAtMs: 1000000005000,
|
|
509
|
+
assembledPrompt: null,
|
|
510
|
+
});
|
|
511
|
+
steps.push(stepHash);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const threadId = "01HX2Q3R4S5T6V7W8X9YZ5" as ThreadId;
|
|
515
|
+
await seedThreads(tmpDir, { [threadId]: steps[2] as CasRef });
|
|
516
|
+
|
|
517
|
+
// Very large quota
|
|
518
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, 1000000, null, false);
|
|
519
|
+
|
|
520
|
+
// Should show all steps (no skipping)
|
|
521
|
+
expect(markdown).not.toMatch(/earlier step/);
|
|
522
|
+
expect(markdown).toMatch(/Step1/);
|
|
523
|
+
expect(markdown).toMatch(/Step2/);
|
|
524
|
+
expect(markdown).toMatch(/Step3/);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
test("test 6: quota with --before parameter", async () => {
|
|
528
|
+
const casDir = join(tmpDir, "cas");
|
|
529
|
+
await mkdir(casDir, { recursive: true });
|
|
530
|
+
const store = await openStore(casDir);
|
|
531
|
+
const schemas = await registerUwfSchemas(store);
|
|
532
|
+
const detailSchemas = await registerDetailSchemas(store);
|
|
533
|
+
|
|
534
|
+
const workflowHash = await store.cas.put(schemas.workflow, {
|
|
535
|
+
name: "test-wf",
|
|
536
|
+
description: "desc",
|
|
537
|
+
roles: {
|
|
538
|
+
worker: {
|
|
539
|
+
description: "Worker",
|
|
540
|
+
goal: "You are a worker agent.",
|
|
541
|
+
capabilities: [],
|
|
542
|
+
procedure: "Do the work.",
|
|
543
|
+
output: "Summarize the work.",
|
|
544
|
+
meta: "placeholder00" as CasRef,
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
conditions: {},
|
|
548
|
+
graph: {},
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
const startHash = await store.cas.put(schemas.startNode, {
|
|
552
|
+
workflow: workflowHash,
|
|
553
|
+
prompt: "Test task",
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
const outputHash = await store.cas.put(schemas.workflow, {
|
|
557
|
+
name: "out",
|
|
558
|
+
description: "",
|
|
559
|
+
roles: {},
|
|
560
|
+
conditions: {},
|
|
561
|
+
graph: {},
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// Create 5 steps
|
|
565
|
+
const steps: CasRef[] = [];
|
|
566
|
+
for (let i = 1; i <= 5; i++) {
|
|
567
|
+
const content = generateContent(300, `Step${i}`);
|
|
568
|
+
const turnHash = await store.cas.put(detailSchemas.turn, {
|
|
569
|
+
index: 0,
|
|
570
|
+
role: "assistant",
|
|
571
|
+
content,
|
|
572
|
+
toolCalls: null,
|
|
573
|
+
reasoning: null,
|
|
574
|
+
});
|
|
575
|
+
const detailHash = await store.cas.put(detailSchemas.detail, {
|
|
576
|
+
sessionId: `session-${i}`,
|
|
577
|
+
model: "test-model",
|
|
578
|
+
duration: 1000,
|
|
579
|
+
turnCount: 1,
|
|
580
|
+
turns: [turnHash],
|
|
581
|
+
});
|
|
582
|
+
const stepHash = await store.cas.put(schemas.stepNode, {
|
|
583
|
+
start: startHash,
|
|
584
|
+
prev: steps[i - 2] ?? null,
|
|
585
|
+
role: "worker",
|
|
586
|
+
output: outputHash,
|
|
587
|
+
detail: detailHash,
|
|
588
|
+
agent: "uwf-test",
|
|
589
|
+
startedAtMs: 1000000000000,
|
|
590
|
+
completedAtMs: 1000000005000,
|
|
591
|
+
assembledPrompt: null,
|
|
592
|
+
});
|
|
593
|
+
steps.push(stepHash);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const threadId = "01HX2Q3R4S5T6V7W8X9YZ6" as ThreadId;
|
|
597
|
+
await seedThreads(tmpDir, { [threadId]: steps[4] as CasRef });
|
|
598
|
+
|
|
599
|
+
// Use --before to limit to steps 1-2, then set quota that allows only 1
|
|
600
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, 500, steps[2] as CasRef, false);
|
|
601
|
+
|
|
602
|
+
// Should not contain Step3 or later
|
|
603
|
+
expect(markdown).not.toMatch(/Step3/);
|
|
604
|
+
expect(markdown).not.toMatch(/Step4/);
|
|
605
|
+
expect(markdown).not.toMatch(/Step5/);
|
|
606
|
+
|
|
607
|
+
// Quota should select most recent of candidates (Step2)
|
|
608
|
+
expect(markdown).toMatch(/Step2/);
|
|
609
|
+
|
|
610
|
+
// Quota enforcement (allow ~200 char tolerance)
|
|
611
|
+
expect(markdown.length).toBeLessThanOrEqual(700);
|
|
612
|
+
});
|
|
613
|
+
});
|