@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,717 @@
|
|
|
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, type Store } from "@ocas/core";
|
|
5
|
+
import type { CasRef, ThreadId } from "@united-workforce/protocol";
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
7
|
+
import { cmdThreadRead, THREAD_READ_DEFAULT_QUOTA } from "../commands/thread.js";
|
|
8
|
+
import type { UwfStore } from "../store.js";
|
|
9
|
+
import { createUwfStore } from "../store.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 makeUwfStore(storageRoot: string): Promise<UwfStore> {
|
|
53
|
+
const casDir = join(storageRoot, "cas");
|
|
54
|
+
await mkdir(casDir, { recursive: true });
|
|
55
|
+
process.env.OCAS_HOME = casDir;
|
|
56
|
+
return createUwfStore(storageRoot);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function registerDetailSchemas(store: Store) {
|
|
60
|
+
await bootstrap(store);
|
|
61
|
+
const [turn, detail] = await Promise.all([
|
|
62
|
+
putSchema(store, TURN_SCHEMA),
|
|
63
|
+
putSchema(store, DETAIL_SCHEMA),
|
|
64
|
+
]);
|
|
65
|
+
return { turn, detail };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ── fixture ───────────────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
let tmpDir: string;
|
|
71
|
+
|
|
72
|
+
beforeEach(async () => {
|
|
73
|
+
tmpDir = await mkdtemp(join(tmpdir(), "cli-uwf-test-"));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
afterEach(async () => {
|
|
77
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// ── thread read XML tag isolation ─────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
describe("thread read XML tag isolation", () => {
|
|
83
|
+
test("scenario 1: wraps output in XML tags instead of heading", async () => {
|
|
84
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
85
|
+
const detailSchemas = await registerDetailSchemas(uwf.store);
|
|
86
|
+
|
|
87
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
88
|
+
name: "test-wf",
|
|
89
|
+
description: "desc",
|
|
90
|
+
roles: {
|
|
91
|
+
planner: {
|
|
92
|
+
description: "Planner",
|
|
93
|
+
goal: "You are a planning agent. Your task is to...",
|
|
94
|
+
capabilities: [],
|
|
95
|
+
procedure: "Plan the work.",
|
|
96
|
+
output: "Summarize the plan.",
|
|
97
|
+
meta: "placeholder00" as CasRef,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
conditions: {},
|
|
101
|
+
graph: {},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
105
|
+
workflow: workflowHash,
|
|
106
|
+
prompt: "Fix issue #459",
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
110
|
+
name: "out",
|
|
111
|
+
description: "",
|
|
112
|
+
roles: {},
|
|
113
|
+
conditions: {},
|
|
114
|
+
graph: {},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const turnHash = await uwf.store.cas.put(detailSchemas.turn, {
|
|
118
|
+
index: 0,
|
|
119
|
+
role: "assistant",
|
|
120
|
+
content:
|
|
121
|
+
"---\nstatus: ready\nplan: CMWGHQKT58RY4\n---\n\n# Analysis Complete\n## Issue Summary\nThe issue requires XML tag isolation.",
|
|
122
|
+
toolCalls: null,
|
|
123
|
+
reasoning: null,
|
|
124
|
+
});
|
|
125
|
+
const detailHash = await uwf.store.cas.put(detailSchemas.detail, {
|
|
126
|
+
sessionId: "sx",
|
|
127
|
+
model: "mx",
|
|
128
|
+
duration: 500,
|
|
129
|
+
turnCount: 1,
|
|
130
|
+
turns: [turnHash],
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const stepHash = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
134
|
+
start: startHash,
|
|
135
|
+
prev: null,
|
|
136
|
+
role: "planner",
|
|
137
|
+
output: outputHash,
|
|
138
|
+
detail: detailHash,
|
|
139
|
+
agent: "uwf-claude-code",
|
|
140
|
+
startedAtMs: 1000000000000,
|
|
141
|
+
completedAtMs: 1000000005000,
|
|
142
|
+
assembledPrompt: null,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const threadId = "01JTEST0000000000000001" as ThreadId;
|
|
146
|
+
await seedThreads(tmpDir, { [threadId]: stepHash });
|
|
147
|
+
|
|
148
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, THREAD_READ_DEFAULT_QUOTA, null, false);
|
|
149
|
+
|
|
150
|
+
// Should wrap output in XML tags
|
|
151
|
+
expect(markdown).toContain("<output>");
|
|
152
|
+
expect(markdown).toContain("</output>");
|
|
153
|
+
|
|
154
|
+
// Should not have ### Content heading
|
|
155
|
+
expect(markdown).not.toContain("### Content");
|
|
156
|
+
|
|
157
|
+
// Should preserve markdown headings inside output tags
|
|
158
|
+
expect(markdown).toContain("# Analysis Complete");
|
|
159
|
+
expect(markdown).toContain("## Issue Summary");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("scenario 2: wraps prompt in XML tags", async () => {
|
|
163
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
164
|
+
const detailSchemas = await registerDetailSchemas(uwf.store);
|
|
165
|
+
|
|
166
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
167
|
+
name: "test-wf",
|
|
168
|
+
description: "desc",
|
|
169
|
+
roles: {
|
|
170
|
+
planner: {
|
|
171
|
+
description: "Planner",
|
|
172
|
+
goal: "You are a planning agent. Your task is to analyze and plan.",
|
|
173
|
+
capabilities: [],
|
|
174
|
+
procedure: "Plan the work.",
|
|
175
|
+
output: "Summarize the plan.",
|
|
176
|
+
meta: "placeholder00" as CasRef,
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
conditions: {},
|
|
180
|
+
graph: {},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
184
|
+
workflow: workflowHash,
|
|
185
|
+
prompt: "Fix issue",
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
189
|
+
name: "out",
|
|
190
|
+
description: "",
|
|
191
|
+
roles: {},
|
|
192
|
+
conditions: {},
|
|
193
|
+
graph: {},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const turnHash = await uwf.store.cas.put(detailSchemas.turn, {
|
|
197
|
+
index: 0,
|
|
198
|
+
role: "assistant",
|
|
199
|
+
content: "---\nstatus: ready\n---\n\nContent here...",
|
|
200
|
+
toolCalls: null,
|
|
201
|
+
reasoning: null,
|
|
202
|
+
});
|
|
203
|
+
const detailHash = await uwf.store.cas.put(detailSchemas.detail, {
|
|
204
|
+
sessionId: "sx",
|
|
205
|
+
model: "mx",
|
|
206
|
+
duration: 500,
|
|
207
|
+
turnCount: 1,
|
|
208
|
+
turns: [turnHash],
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const stepHash = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
212
|
+
start: startHash,
|
|
213
|
+
prev: null,
|
|
214
|
+
role: "planner",
|
|
215
|
+
output: outputHash,
|
|
216
|
+
detail: detailHash,
|
|
217
|
+
agent: "uwf-claude-code",
|
|
218
|
+
startedAtMs: 1000000000000,
|
|
219
|
+
completedAtMs: 1000000005000,
|
|
220
|
+
assembledPrompt: null,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const threadId = "01JTEST0000000000000002" as ThreadId;
|
|
224
|
+
await seedThreads(tmpDir, { [threadId]: stepHash });
|
|
225
|
+
|
|
226
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, THREAD_READ_DEFAULT_QUOTA, null, false);
|
|
227
|
+
|
|
228
|
+
// Should wrap prompt in XML tags
|
|
229
|
+
expect(markdown).toContain("<prompt>");
|
|
230
|
+
expect(markdown).toContain("</prompt>");
|
|
231
|
+
expect(markdown).toContain("You are a planning agent. Your task is to analyze and plan.");
|
|
232
|
+
|
|
233
|
+
// Should not have ### Prompt heading
|
|
234
|
+
expect(markdown).not.toContain("### Prompt");
|
|
235
|
+
|
|
236
|
+
// Should wrap output in XML tags
|
|
237
|
+
expect(markdown).toContain("<output>");
|
|
238
|
+
expect(markdown).toContain("</output>");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("scenario 3: same role repeated does not show prompt twice", async () => {
|
|
242
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
243
|
+
|
|
244
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
245
|
+
name: "test-wf",
|
|
246
|
+
description: "desc",
|
|
247
|
+
roles: {
|
|
248
|
+
writer: {
|
|
249
|
+
description: "Writer",
|
|
250
|
+
goal: "You are a writer agent.",
|
|
251
|
+
capabilities: [],
|
|
252
|
+
procedure: "Write content.",
|
|
253
|
+
output: "Summarize writing.",
|
|
254
|
+
meta: "placeholder00" as CasRef,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
conditions: {},
|
|
258
|
+
graph: {},
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
262
|
+
workflow: workflowHash,
|
|
263
|
+
prompt: "Write something",
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
267
|
+
name: "out",
|
|
268
|
+
description: "",
|
|
269
|
+
roles: {},
|
|
270
|
+
conditions: {},
|
|
271
|
+
graph: {},
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const step1 = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
275
|
+
start: startHash,
|
|
276
|
+
prev: null,
|
|
277
|
+
role: "writer",
|
|
278
|
+
output: outputHash,
|
|
279
|
+
detail: null,
|
|
280
|
+
agent: "uwf-test",
|
|
281
|
+
startedAtMs: 1000000000000,
|
|
282
|
+
completedAtMs: 1000000005000,
|
|
283
|
+
assembledPrompt: null,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const step2 = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
287
|
+
start: startHash,
|
|
288
|
+
prev: step1 as CasRef,
|
|
289
|
+
role: "writer",
|
|
290
|
+
output: outputHash,
|
|
291
|
+
detail: null,
|
|
292
|
+
agent: "uwf-test",
|
|
293
|
+
startedAtMs: 1000000000000,
|
|
294
|
+
completedAtMs: 1000000005000,
|
|
295
|
+
assembledPrompt: null,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const threadId = "01JTEST0000000000000003" as ThreadId;
|
|
299
|
+
await seedThreads(tmpDir, { [threadId]: step2 });
|
|
300
|
+
|
|
301
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, THREAD_READ_DEFAULT_QUOTA, null, false);
|
|
302
|
+
|
|
303
|
+
// Should only show prompt tags once
|
|
304
|
+
const promptCount = (markdown.match(/<prompt>/g) ?? []).length;
|
|
305
|
+
expect(promptCount).toBe(1);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("scenario 4: step with no detail shows no output tags", async () => {
|
|
309
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
310
|
+
|
|
311
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
312
|
+
name: "test-wf",
|
|
313
|
+
description: "desc",
|
|
314
|
+
roles: {
|
|
315
|
+
worker: {
|
|
316
|
+
description: "Worker",
|
|
317
|
+
goal: "You are a worker agent.",
|
|
318
|
+
capabilities: [],
|
|
319
|
+
procedure: "Do work.",
|
|
320
|
+
output: "Summarize work.",
|
|
321
|
+
meta: "placeholder00" as CasRef,
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
conditions: {},
|
|
325
|
+
graph: {},
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
329
|
+
workflow: workflowHash,
|
|
330
|
+
prompt: "Do stuff",
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
334
|
+
name: "out",
|
|
335
|
+
description: "",
|
|
336
|
+
roles: {},
|
|
337
|
+
conditions: {},
|
|
338
|
+
graph: {},
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const stepHash = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
342
|
+
start: startHash,
|
|
343
|
+
prev: null,
|
|
344
|
+
role: "worker",
|
|
345
|
+
output: outputHash,
|
|
346
|
+
detail: null,
|
|
347
|
+
agent: "uwf-test",
|
|
348
|
+
startedAtMs: 1000000000000,
|
|
349
|
+
completedAtMs: 1000000005000,
|
|
350
|
+
assembledPrompt: null,
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const threadId = "01JTEST0000000000000004" as ThreadId;
|
|
354
|
+
await seedThreads(tmpDir, { [threadId]: stepHash });
|
|
355
|
+
|
|
356
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, THREAD_READ_DEFAULT_QUOTA, null, false);
|
|
357
|
+
|
|
358
|
+
// Should not have output tags
|
|
359
|
+
expect(markdown).not.toContain("<output>");
|
|
360
|
+
expect(markdown).not.toContain("</output>");
|
|
361
|
+
|
|
362
|
+
// Step header should still be displayed
|
|
363
|
+
expect(markdown).toContain("## Step 1: worker");
|
|
364
|
+
|
|
365
|
+
// Prompt should still be shown
|
|
366
|
+
expect(markdown).toContain("<prompt>");
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
test("scenario 5: empty content shows no output tags", async () => {
|
|
370
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
371
|
+
|
|
372
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
373
|
+
name: "test-wf",
|
|
374
|
+
description: "desc",
|
|
375
|
+
roles: {},
|
|
376
|
+
conditions: {},
|
|
377
|
+
graph: {},
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
381
|
+
workflow: workflowHash,
|
|
382
|
+
prompt: "Do stuff",
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
386
|
+
name: "out",
|
|
387
|
+
description: "",
|
|
388
|
+
roles: {},
|
|
389
|
+
conditions: {},
|
|
390
|
+
graph: {},
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// A detail ref that doesn't exist → extractLastAssistantContent returns null
|
|
394
|
+
const missingDetailRef = "missingdetail0" as CasRef;
|
|
395
|
+
|
|
396
|
+
const stepHash = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
397
|
+
start: startHash,
|
|
398
|
+
prev: null,
|
|
399
|
+
role: "worker",
|
|
400
|
+
output: outputHash,
|
|
401
|
+
detail: missingDetailRef,
|
|
402
|
+
agent: "uwf-test",
|
|
403
|
+
startedAtMs: 1000000000000,
|
|
404
|
+
completedAtMs: 1000000005000,
|
|
405
|
+
assembledPrompt: null,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
const threadId = "01JTEST0000000000000005" as ThreadId;
|
|
409
|
+
await seedThreads(tmpDir, { [threadId]: stepHash });
|
|
410
|
+
|
|
411
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, THREAD_READ_DEFAULT_QUOTA, null, false);
|
|
412
|
+
|
|
413
|
+
// Should not have output tags
|
|
414
|
+
expect(markdown).not.toContain("<output>");
|
|
415
|
+
expect(markdown).not.toContain("</output>");
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
test("scenario 6: thread read with --start flag shows task section", async () => {
|
|
419
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
420
|
+
|
|
421
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
422
|
+
name: "test-wf",
|
|
423
|
+
description: "desc",
|
|
424
|
+
roles: {
|
|
425
|
+
roleA: {
|
|
426
|
+
description: "Role A",
|
|
427
|
+
goal: "Goal for roleA",
|
|
428
|
+
capabilities: [],
|
|
429
|
+
procedure: "Do stuff.",
|
|
430
|
+
output: "Output.",
|
|
431
|
+
meta: "placeholder00" as CasRef,
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
conditions: {},
|
|
435
|
+
graph: {},
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
439
|
+
workflow: workflowHash,
|
|
440
|
+
prompt: "Initial prompt",
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
444
|
+
name: "out",
|
|
445
|
+
description: "",
|
|
446
|
+
roles: {},
|
|
447
|
+
conditions: {},
|
|
448
|
+
graph: {},
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
const stepHash = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
452
|
+
start: startHash,
|
|
453
|
+
prev: null,
|
|
454
|
+
role: "roleA",
|
|
455
|
+
output: outputHash,
|
|
456
|
+
detail: null,
|
|
457
|
+
agent: "uwf-test",
|
|
458
|
+
startedAtMs: 1000000000000,
|
|
459
|
+
completedAtMs: 1000000005000,
|
|
460
|
+
assembledPrompt: null,
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
const threadId = "01JTEST0000000000000006" as ThreadId;
|
|
464
|
+
await seedThreads(tmpDir, { [threadId]: stepHash });
|
|
465
|
+
|
|
466
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, THREAD_READ_DEFAULT_QUOTA, null, true);
|
|
467
|
+
|
|
468
|
+
// Should include task section
|
|
469
|
+
expect(markdown).toContain("# Thread");
|
|
470
|
+
expect(markdown).toContain("## Task");
|
|
471
|
+
expect(markdown).toContain("Initial prompt");
|
|
472
|
+
|
|
473
|
+
// Prompts should use XML tags
|
|
474
|
+
expect(markdown).toContain("<prompt>");
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
test("scenario 7: thread read with --before parameter", async () => {
|
|
478
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
479
|
+
|
|
480
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
481
|
+
name: "test-wf",
|
|
482
|
+
description: "desc",
|
|
483
|
+
roles: {
|
|
484
|
+
roleA: {
|
|
485
|
+
description: "Role A",
|
|
486
|
+
goal: "Goal for roleA",
|
|
487
|
+
capabilities: [],
|
|
488
|
+
procedure: "Do stuff.",
|
|
489
|
+
output: "Output.",
|
|
490
|
+
meta: "placeholder00" as CasRef,
|
|
491
|
+
},
|
|
492
|
+
roleB: {
|
|
493
|
+
description: "Role B",
|
|
494
|
+
goal: "Goal for roleB",
|
|
495
|
+
capabilities: [],
|
|
496
|
+
procedure: "Do stuff.",
|
|
497
|
+
output: "Output.",
|
|
498
|
+
meta: "placeholder00" as CasRef,
|
|
499
|
+
},
|
|
500
|
+
roleC: {
|
|
501
|
+
description: "Role C",
|
|
502
|
+
goal: "Goal for roleC",
|
|
503
|
+
capabilities: [],
|
|
504
|
+
procedure: "Do stuff.",
|
|
505
|
+
output: "Output.",
|
|
506
|
+
meta: "placeholder00" as CasRef,
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
conditions: {},
|
|
510
|
+
graph: {},
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
514
|
+
workflow: workflowHash,
|
|
515
|
+
prompt: "Initial prompt",
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
519
|
+
name: "out",
|
|
520
|
+
description: "",
|
|
521
|
+
roles: {},
|
|
522
|
+
conditions: {},
|
|
523
|
+
graph: {},
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
const step1 = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
527
|
+
start: startHash,
|
|
528
|
+
prev: null,
|
|
529
|
+
role: "roleA",
|
|
530
|
+
output: outputHash,
|
|
531
|
+
detail: null,
|
|
532
|
+
agent: "uwf-test",
|
|
533
|
+
startedAtMs: 1000000000000,
|
|
534
|
+
completedAtMs: 1000000005000,
|
|
535
|
+
assembledPrompt: null,
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
const step2 = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
539
|
+
start: startHash,
|
|
540
|
+
prev: step1 as CasRef,
|
|
541
|
+
role: "roleB",
|
|
542
|
+
output: outputHash,
|
|
543
|
+
detail: null,
|
|
544
|
+
agent: "uwf-test",
|
|
545
|
+
startedAtMs: 1000000000000,
|
|
546
|
+
completedAtMs: 1000000005000,
|
|
547
|
+
assembledPrompt: null,
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
const step3 = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
551
|
+
start: startHash,
|
|
552
|
+
prev: step2 as CasRef,
|
|
553
|
+
role: "roleC",
|
|
554
|
+
output: outputHash,
|
|
555
|
+
detail: null,
|
|
556
|
+
agent: "uwf-test",
|
|
557
|
+
startedAtMs: 1000000000000,
|
|
558
|
+
completedAtMs: 1000000005000,
|
|
559
|
+
assembledPrompt: null,
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
const threadId = "01JTEST0000000000000007" as ThreadId;
|
|
563
|
+
await seedThreads(tmpDir, { [threadId]: step3 });
|
|
564
|
+
|
|
565
|
+
const markdown = await cmdThreadRead(
|
|
566
|
+
tmpDir,
|
|
567
|
+
threadId,
|
|
568
|
+
THREAD_READ_DEFAULT_QUOTA,
|
|
569
|
+
step2 as CasRef,
|
|
570
|
+
false,
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
// Should only show roleA
|
|
574
|
+
expect(markdown).toContain("roleA");
|
|
575
|
+
expect(markdown).not.toContain("roleB");
|
|
576
|
+
expect(markdown).not.toContain("roleC");
|
|
577
|
+
|
|
578
|
+
// Should use XML tags
|
|
579
|
+
expect(markdown).toContain("<prompt>");
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
test("scenario 9: special characters in content are preserved", async () => {
|
|
583
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
584
|
+
const detailSchemas = await registerDetailSchemas(uwf.store);
|
|
585
|
+
|
|
586
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
587
|
+
name: "test-wf",
|
|
588
|
+
description: "desc",
|
|
589
|
+
roles: {
|
|
590
|
+
writer: {
|
|
591
|
+
description: "Writer",
|
|
592
|
+
goal: "You are a writer.",
|
|
593
|
+
capabilities: [],
|
|
594
|
+
procedure: "Write content.",
|
|
595
|
+
output: "Summarize.",
|
|
596
|
+
meta: "placeholder00" as CasRef,
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
conditions: {},
|
|
600
|
+
graph: {},
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
604
|
+
workflow: workflowHash,
|
|
605
|
+
prompt: "Write something",
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
609
|
+
name: "out",
|
|
610
|
+
description: "",
|
|
611
|
+
roles: {},
|
|
612
|
+
conditions: {},
|
|
613
|
+
graph: {},
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
const turnHash = await uwf.store.cas.put(detailSchemas.turn, {
|
|
617
|
+
index: 0,
|
|
618
|
+
role: "assistant",
|
|
619
|
+
content: "Content with <special> & characters > like <this>",
|
|
620
|
+
toolCalls: null,
|
|
621
|
+
reasoning: null,
|
|
622
|
+
});
|
|
623
|
+
const detailHash = await uwf.store.cas.put(detailSchemas.detail, {
|
|
624
|
+
sessionId: "sx",
|
|
625
|
+
model: "mx",
|
|
626
|
+
duration: 500,
|
|
627
|
+
turnCount: 1,
|
|
628
|
+
turns: [turnHash],
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
const stepHash = await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
632
|
+
start: startHash,
|
|
633
|
+
prev: null,
|
|
634
|
+
role: "writer",
|
|
635
|
+
output: outputHash,
|
|
636
|
+
detail: detailHash,
|
|
637
|
+
agent: "uwf-test",
|
|
638
|
+
startedAtMs: 1000000000000,
|
|
639
|
+
completedAtMs: 1000000005000,
|
|
640
|
+
assembledPrompt: null,
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
const threadId = "01JTEST0000000000000008" as ThreadId;
|
|
644
|
+
await seedThreads(tmpDir, { [threadId]: stepHash });
|
|
645
|
+
|
|
646
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, THREAD_READ_DEFAULT_QUOTA, null, false);
|
|
647
|
+
|
|
648
|
+
// Special characters should be preserved as-is
|
|
649
|
+
expect(markdown).toContain("Content with <special> & characters > like <this>");
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
test("scenario 10: quota limit with XML tags", async () => {
|
|
653
|
+
const uwf = await makeUwfStore(tmpDir);
|
|
654
|
+
|
|
655
|
+
const workflowHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
656
|
+
name: "test-wf",
|
|
657
|
+
description: "desc",
|
|
658
|
+
roles: {
|
|
659
|
+
roleA: {
|
|
660
|
+
description: "Role A",
|
|
661
|
+
goal: "Goal for roleA",
|
|
662
|
+
capabilities: [],
|
|
663
|
+
procedure: "Do stuff.",
|
|
664
|
+
output: "Output.",
|
|
665
|
+
meta: "placeholder00" as CasRef,
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
conditions: {},
|
|
669
|
+
graph: {},
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
const startHash = await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
673
|
+
workflow: workflowHash,
|
|
674
|
+
prompt: "Initial prompt",
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
const outputHash = await uwf.store.cas.put(uwf.schemas.workflow, {
|
|
678
|
+
name: "out",
|
|
679
|
+
description: "",
|
|
680
|
+
roles: {},
|
|
681
|
+
conditions: {},
|
|
682
|
+
graph: {},
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
const steps: CasRef[] = [];
|
|
686
|
+
let prev: CasRef | null = null;
|
|
687
|
+
for (let i = 0; i < 5; i++) {
|
|
688
|
+
const step = (await uwf.store.cas.put(uwf.schemas.stepNode, {
|
|
689
|
+
start: startHash,
|
|
690
|
+
prev,
|
|
691
|
+
role: "roleA",
|
|
692
|
+
output: outputHash,
|
|
693
|
+
detail: null,
|
|
694
|
+
agent: "uwf-test",
|
|
695
|
+
startedAtMs: 1000000000000,
|
|
696
|
+
completedAtMs: 1000000005000,
|
|
697
|
+
assembledPrompt: null,
|
|
698
|
+
})) as CasRef;
|
|
699
|
+
steps.push(step);
|
|
700
|
+
prev = step;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const threadId = "01JTEST0000000000000009" as ThreadId;
|
|
704
|
+
await seedThreads(tmpDir, { [threadId]: steps[steps.length - 1]! });
|
|
705
|
+
|
|
706
|
+
// Use very small quota
|
|
707
|
+
const markdown = await cmdThreadRead(tmpDir, threadId, 1, null, false);
|
|
708
|
+
|
|
709
|
+
// Should have skip hint
|
|
710
|
+
expect(markdown).toContain("earlier step");
|
|
711
|
+
|
|
712
|
+
// Should have XML tags for displayed steps
|
|
713
|
+
if (markdown.includes("<prompt>")) {
|
|
714
|
+
expect(markdown).toContain("</prompt>");
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
});
|