@goondan/openharness-base 0.1.1 → 0.1.3
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/dist/index.d.ts +3 -3
- package/dist/index.js +6 -6
- package/package.json +2 -2
- package/src/__tests__/{context-message.test.ts → basic-system-prompt.test.ts} +18 -66
- package/src/extensions/{context-message.ts → basic-system-prompt.ts} +5 -5
- package/src/index.ts +1 -1
- package/dist/extensions/message-integrity.d.ts +0 -8
- package/dist/extensions/message-integrity.d.ts.map +0 -1
- package/dist/extensions/message-integrity.js +0 -88
- package/dist/extensions/message-integrity.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Extension, ToolDefinition } from '@goondan/openharness-types';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* BasicSystemPrompt extension — prepends a system message to the conversation
|
|
5
5
|
* at the start of every turn.
|
|
6
6
|
*
|
|
7
7
|
* Priority 10 (HIGH) ensures it runs before other turn middleware.
|
|
8
8
|
*/
|
|
9
|
-
declare function
|
|
9
|
+
declare function BasicSystemPrompt(text: string): Extension;
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* MessageWindow extension — truncates conversation history to keep only
|
|
@@ -69,4 +69,4 @@ interface WaitToolConfig {
|
|
|
69
69
|
}
|
|
70
70
|
declare function WaitTool(config?: WaitToolConfig): ToolDefinition;
|
|
71
71
|
|
|
72
|
-
export { BashTool, type BashToolConfig,
|
|
72
|
+
export { BashTool, type BashToolConfig, BasicSystemPrompt, CompactionSummarize, FileListTool, FileReadTool, FileWriteTool, HttpFetchTool, JsonQueryTool, Logging, MessageWindow, RequiredToolsGuard, TextTransformTool, ToolSearch, WaitTool, type WaitToolConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// src/extensions/
|
|
1
|
+
// src/extensions/basic-system-prompt.ts
|
|
2
2
|
import { randomUUID } from "crypto";
|
|
3
|
-
function
|
|
3
|
+
function BasicSystemPrompt(text) {
|
|
4
4
|
return {
|
|
5
|
-
name: "
|
|
5
|
+
name: "basic-system-prompt",
|
|
6
6
|
register(api) {
|
|
7
7
|
api.pipeline.register(
|
|
8
8
|
"turn",
|
|
@@ -10,13 +10,13 @@ function ContextMessage(text) {
|
|
|
10
10
|
ctx.conversation.emit({
|
|
11
11
|
type: "append",
|
|
12
12
|
message: {
|
|
13
|
-
id: `
|
|
13
|
+
id: `sys-${randomUUID()}`,
|
|
14
14
|
data: {
|
|
15
15
|
role: "system",
|
|
16
16
|
content: text
|
|
17
17
|
},
|
|
18
18
|
metadata: {
|
|
19
|
-
__createdBy: "
|
|
19
|
+
__createdBy: "basic-system-prompt"
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
});
|
|
@@ -490,8 +490,8 @@ function WaitTool(config = {}) {
|
|
|
490
490
|
}
|
|
491
491
|
export {
|
|
492
492
|
BashTool,
|
|
493
|
+
BasicSystemPrompt,
|
|
493
494
|
CompactionSummarize,
|
|
494
|
-
ContextMessage,
|
|
495
495
|
FileListTool,
|
|
496
496
|
FileReadTool,
|
|
497
497
|
FileWriteTool,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goondan/openharness-base",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@goondan/openharness-types": "0.1.
|
|
12
|
+
"@goondan/openharness-types": "0.1.3"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@types/node": "^25.5.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import { BasicSystemPrompt } from "../extensions/basic-system-prompt.js";
|
|
3
3
|
import type {
|
|
4
4
|
ExtensionApi,
|
|
5
5
|
TurnMiddleware,
|
|
@@ -97,19 +97,17 @@ const stubTurnResult: TurnResult = {
|
|
|
97
97
|
// Tests
|
|
98
98
|
// ---------------------------------------------------------------------------
|
|
99
99
|
|
|
100
|
-
describe("
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
expect(ext.name).toBe("context-message");
|
|
100
|
+
describe("BasicSystemPrompt", () => {
|
|
101
|
+
it("creates an Extension with name 'basic-system-prompt'", () => {
|
|
102
|
+
const ext = BasicSystemPrompt("You are helpful.");
|
|
103
|
+
expect(ext.name).toBe("basic-system-prompt");
|
|
105
104
|
});
|
|
106
105
|
|
|
107
|
-
// Test 2: register() adds turn middleware via api.pipeline.register
|
|
108
106
|
it("register() calls api.pipeline.register with level 'turn'", () => {
|
|
109
107
|
const conversation = makeMockConversationState();
|
|
110
108
|
const { api, registeredMiddleware } = makeMockApi(conversation);
|
|
111
109
|
|
|
112
|
-
const ext =
|
|
110
|
+
const ext = BasicSystemPrompt("You are helpful.");
|
|
113
111
|
ext.register(api);
|
|
114
112
|
|
|
115
113
|
expect(api.pipeline.register).toHaveBeenCalledOnce();
|
|
@@ -118,49 +116,21 @@ describe("ContextMessage", () => {
|
|
|
118
116
|
expect(typeof registeredMiddleware[0].handler).toBe("function");
|
|
119
117
|
});
|
|
120
118
|
|
|
121
|
-
// Test 3: middleware is registered with HIGH priority (low number)
|
|
122
119
|
it("registers turn middleware with priority 10 (high priority)", () => {
|
|
123
120
|
const conversation = makeMockConversationState();
|
|
124
121
|
const { api, registeredMiddleware } = makeMockApi(conversation);
|
|
125
122
|
|
|
126
|
-
const ext =
|
|
123
|
+
const ext = BasicSystemPrompt("You are helpful.");
|
|
127
124
|
ext.register(api);
|
|
128
125
|
|
|
129
126
|
expect(registeredMiddleware[0].options?.priority).toBe(10);
|
|
130
127
|
});
|
|
131
128
|
|
|
132
|
-
|
|
133
|
-
it("middleware emits append event with system message matching the text argument", async () => {
|
|
129
|
+
it("middleware appends a system message and calls next()", async () => {
|
|
134
130
|
const conversation = makeMockConversationState();
|
|
135
131
|
const { api, registeredMiddleware } = makeMockApi(conversation);
|
|
136
|
-
const systemText = "You are a helpful assistant.";
|
|
137
132
|
|
|
138
|
-
const ext =
|
|
139
|
-
ext.register(api);
|
|
140
|
-
|
|
141
|
-
const middleware = registeredMiddleware[0].handler;
|
|
142
|
-
const ctx = makeTurnContext(conversation);
|
|
143
|
-
const next = vi.fn(async () => stubTurnResult);
|
|
144
|
-
|
|
145
|
-
await middleware(ctx, next);
|
|
146
|
-
|
|
147
|
-
expect(conversation.emit).toHaveBeenCalledOnce();
|
|
148
|
-
const emitted = conversation.emitted[0];
|
|
149
|
-
expect(emitted.type).toBe("append");
|
|
150
|
-
if (emitted.type === "append") {
|
|
151
|
-
expect(emitted.message.data.role).toBe("system");
|
|
152
|
-
expect(emitted.message.data.content).toBe(systemText);
|
|
153
|
-
expect(emitted.message.metadata?.__createdBy).toBe("context-message");
|
|
154
|
-
expect(typeof emitted.message.id).toBe("string");
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// Test 5: middleware calls next() after emitting
|
|
159
|
-
it("middleware calls next() after emitting the system message", async () => {
|
|
160
|
-
const conversation = makeMockConversationState();
|
|
161
|
-
const { api, registeredMiddleware } = makeMockApi(conversation);
|
|
162
|
-
|
|
163
|
-
const ext = ContextMessage("Some context");
|
|
133
|
+
const ext = BasicSystemPrompt("You are helpful.");
|
|
164
134
|
ext.register(api);
|
|
165
135
|
|
|
166
136
|
const middleware = registeredMiddleware[0].handler;
|
|
@@ -171,33 +141,15 @@ describe("ContextMessage", () => {
|
|
|
171
141
|
|
|
172
142
|
expect(next).toHaveBeenCalledOnce();
|
|
173
143
|
expect(result).toBe(stubTurnResult);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// Test 6: multiple ContextMessage extensions → multiple system messages
|
|
177
|
-
it("multiple ContextMessage extensions each prepend their own system message", async () => {
|
|
178
|
-
const conversation = makeMockConversationState();
|
|
179
|
-
const { api: api1, registeredMiddleware: rm1 } = makeMockApi(conversation);
|
|
180
|
-
const { api: api2, registeredMiddleware: rm2 } = makeMockApi(conversation);
|
|
181
|
-
|
|
182
|
-
const ext1 = ContextMessage("First context");
|
|
183
|
-
const ext2 = ContextMessage("Second context");
|
|
184
144
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
expect(conversation.emitted).toHaveLength(2);
|
|
195
|
-
|
|
196
|
-
const texts = conversation.emitted
|
|
197
|
-
.filter((e): e is Extract<typeof e, { type: "append" }> => e.type === "append")
|
|
198
|
-
.map((e) => e.message.data.content);
|
|
199
|
-
|
|
200
|
-
expect(texts).toContain("First context");
|
|
201
|
-
expect(texts).toContain("Second context");
|
|
145
|
+
// Verify system message was emitted
|
|
146
|
+
expect(conversation.emit).toHaveBeenCalledOnce();
|
|
147
|
+
const emittedEvent = conversation.emitted[0];
|
|
148
|
+
expect(emittedEvent.type).toBe("append");
|
|
149
|
+
if (emittedEvent.type === "append") {
|
|
150
|
+
expect(emittedEvent.message.data.role).toBe("system");
|
|
151
|
+
expect(emittedEvent.message.data.content).toBe("You are helpful.");
|
|
152
|
+
expect(emittedEvent.message.metadata?.__createdBy).toBe("basic-system-prompt");
|
|
153
|
+
}
|
|
202
154
|
});
|
|
203
155
|
});
|
|
@@ -2,14 +2,14 @@ import type { Extension, ExtensionApi } from "@goondan/openharness-types";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* BasicSystemPrompt extension — prepends a system message to the conversation
|
|
6
6
|
* at the start of every turn.
|
|
7
7
|
*
|
|
8
8
|
* Priority 10 (HIGH) ensures it runs before other turn middleware.
|
|
9
9
|
*/
|
|
10
|
-
export function
|
|
10
|
+
export function BasicSystemPrompt(text: string): Extension {
|
|
11
11
|
return {
|
|
12
|
-
name: "
|
|
12
|
+
name: "basic-system-prompt",
|
|
13
13
|
|
|
14
14
|
register(api: ExtensionApi): void {
|
|
15
15
|
api.pipeline.register(
|
|
@@ -18,13 +18,13 @@ export function ContextMessage(text: string): Extension {
|
|
|
18
18
|
ctx.conversation.emit({
|
|
19
19
|
type: "append",
|
|
20
20
|
message: {
|
|
21
|
-
id: `
|
|
21
|
+
id: `sys-${randomUUID()}`,
|
|
22
22
|
data: {
|
|
23
23
|
role: "system",
|
|
24
24
|
content: text,
|
|
25
25
|
},
|
|
26
26
|
metadata: {
|
|
27
|
-
__createdBy: "
|
|
27
|
+
__createdBy: "basic-system-prompt",
|
|
28
28
|
},
|
|
29
29
|
},
|
|
30
30
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { BasicSystemPrompt } from "./extensions/basic-system-prompt.js";
|
|
2
2
|
export { MessageWindow } from "./extensions/message-window.js";
|
|
3
3
|
export { CompactionSummarize } from "./extensions/compaction-summarize.js";
|
|
4
4
|
export { Logging } from "./extensions/logging.js";
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { Message } from '../types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Removes messages that would leave invalid tool_result references after trimming.
|
|
4
|
-
* Anthropic requires every tool_result block to map to a tool_use/tool-call block
|
|
5
|
-
* in the immediately previous assistant message.
|
|
6
|
-
*/
|
|
7
|
-
export declare function normalizeRemovalTargets(messages: Message[], initialRemovedIds: ReadonlySet<string>): Set<string>;
|
|
8
|
-
//# sourceMappingURL=message-integrity.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message-integrity.d.ts","sourceRoot":"","sources":["../../src/extensions/message-integrity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAiF3C;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,OAAO,EAAE,EACnB,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC,GACrC,GAAG,CAAC,MAAM,CAAC,CAwBb"}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
function readToolCallId(part) {
|
|
2
|
-
const value = part.toolCallId;
|
|
3
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
4
|
-
return null;
|
|
5
|
-
}
|
|
6
|
-
return value;
|
|
7
|
-
}
|
|
8
|
-
function collectToolCallIds(message) {
|
|
9
|
-
const ids = new Set();
|
|
10
|
-
if (!message) {
|
|
11
|
-
return ids;
|
|
12
|
-
}
|
|
13
|
-
const content = message.data.content;
|
|
14
|
-
if (!Array.isArray(content)) {
|
|
15
|
-
return ids;
|
|
16
|
-
}
|
|
17
|
-
for (const part of content) {
|
|
18
|
-
if (part.type !== 'tool-call') {
|
|
19
|
-
continue;
|
|
20
|
-
}
|
|
21
|
-
const toolCallId = readToolCallId(part);
|
|
22
|
-
if (!toolCallId) {
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
ids.add(toolCallId);
|
|
26
|
-
}
|
|
27
|
-
return ids;
|
|
28
|
-
}
|
|
29
|
-
function collectToolResultIds(message) {
|
|
30
|
-
const content = message.data.content;
|
|
31
|
-
if (!Array.isArray(content)) {
|
|
32
|
-
return [];
|
|
33
|
-
}
|
|
34
|
-
const ids = [];
|
|
35
|
-
for (const part of content) {
|
|
36
|
-
if (part.type !== 'tool-result') {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
const toolCallId = readToolCallId(part);
|
|
40
|
-
if (!toolCallId) {
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
ids.push(toolCallId);
|
|
44
|
-
}
|
|
45
|
-
return ids;
|
|
46
|
-
}
|
|
47
|
-
function hasDanglingToolResult(message, previousMessage) {
|
|
48
|
-
const toolResultIds = collectToolResultIds(message);
|
|
49
|
-
if (toolResultIds.length === 0) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
const previousToolCallIds = collectToolCallIds(previousMessage);
|
|
53
|
-
if (previousToolCallIds.size === 0) {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
for (const toolResultId of toolResultIds) {
|
|
57
|
-
if (!previousToolCallIds.has(toolResultId)) {
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Removes messages that would leave invalid tool_result references after trimming.
|
|
65
|
-
* Anthropic requires every tool_result block to map to a tool_use/tool-call block
|
|
66
|
-
* in the immediately previous assistant message.
|
|
67
|
-
*/
|
|
68
|
-
export function normalizeRemovalTargets(messages, initialRemovedIds) {
|
|
69
|
-
const removedIds = new Set(initialRemovedIds);
|
|
70
|
-
let changed = true;
|
|
71
|
-
while (changed) {
|
|
72
|
-
changed = false;
|
|
73
|
-
let previousRemainingMessage;
|
|
74
|
-
for (const message of messages) {
|
|
75
|
-
if (removedIds.has(message.id)) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (hasDanglingToolResult(message, previousRemainingMessage)) {
|
|
79
|
-
removedIds.add(message.id);
|
|
80
|
-
changed = true;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
previousRemainingMessage = message;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return removedIds;
|
|
87
|
-
}
|
|
88
|
-
//# sourceMappingURL=message-integrity.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message-integrity.js","sourceRoot":"","sources":["../../src/extensions/message-integrity.ts"],"names":[],"mappings":"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"}
|