@goondan/openharness-base 0.1.7 → 0.1.9

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.
Files changed (98) hide show
  1. package/package.json +14 -9
  2. package/dist/extensions/compaction.d.ts +0 -12
  3. package/dist/extensions/compaction.d.ts.map +0 -1
  4. package/dist/extensions/compaction.js +0 -159
  5. package/dist/extensions/compaction.js.map +0 -1
  6. package/dist/extensions/context-message.d.ts +0 -9
  7. package/dist/extensions/context-message.d.ts.map +0 -1
  8. package/dist/extensions/context-message.js +0 -446
  9. package/dist/extensions/context-message.js.map +0 -1
  10. package/dist/extensions/index.d.ts +0 -13
  11. package/dist/extensions/index.d.ts.map +0 -1
  12. package/dist/extensions/index.js +0 -7
  13. package/dist/extensions/index.js.map +0 -1
  14. package/dist/extensions/logging.d.ts +0 -11
  15. package/dist/extensions/logging.d.ts.map +0 -1
  16. package/dist/extensions/logging.js +0 -140
  17. package/dist/extensions/logging.js.map +0 -1
  18. package/dist/extensions/message-window.d.ts +0 -7
  19. package/dist/extensions/message-window.d.ts.map +0 -1
  20. package/dist/extensions/message-window.js +0 -60
  21. package/dist/extensions/message-window.js.map +0 -1
  22. package/dist/extensions/required-tools-guard.d.ts +0 -9
  23. package/dist/extensions/required-tools-guard.d.ts.map +0 -1
  24. package/dist/extensions/required-tools-guard.js +0 -74
  25. package/dist/extensions/required-tools-guard.js.map +0 -1
  26. package/dist/extensions/tool-search.d.ts +0 -10
  27. package/dist/extensions/tool-search.d.ts.map +0 -1
  28. package/dist/extensions/tool-search.js +0 -198
  29. package/dist/extensions/tool-search.js.map +0 -1
  30. package/dist/harness.yaml +0 -503
  31. package/dist/index.d.ts.map +0 -1
  32. package/dist/index.js.map +0 -1
  33. package/dist/manifests/base.d.ts +0 -8
  34. package/dist/manifests/base.d.ts.map +0 -1
  35. package/dist/manifests/base.js +0 -352
  36. package/dist/manifests/base.js.map +0 -1
  37. package/dist/manifests/index.d.ts +0 -3
  38. package/dist/manifests/index.d.ts.map +0 -1
  39. package/dist/manifests/index.js +0 -2
  40. package/dist/manifests/index.js.map +0 -1
  41. package/dist/tools/bash.d.ts +0 -8
  42. package/dist/tools/bash.d.ts.map +0 -1
  43. package/dist/tools/bash.js +0 -119
  44. package/dist/tools/bash.js.map +0 -1
  45. package/dist/tools/file-system.d.ts +0 -12
  46. package/dist/tools/file-system.d.ts.map +0 -1
  47. package/dist/tools/file-system.js +0 -117
  48. package/dist/tools/file-system.js.map +0 -1
  49. package/dist/tools/http-fetch.d.ts +0 -8
  50. package/dist/tools/http-fetch.d.ts.map +0 -1
  51. package/dist/tools/http-fetch.js +0 -149
  52. package/dist/tools/http-fetch.js.map +0 -1
  53. package/dist/tools/index.d.ts +0 -7
  54. package/dist/tools/index.d.ts.map +0 -1
  55. package/dist/tools/index.js +0 -7
  56. package/dist/tools/index.js.map +0 -1
  57. package/dist/tools/json-query.d.ts +0 -12
  58. package/dist/tools/json-query.d.ts.map +0 -1
  59. package/dist/tools/json-query.js +0 -176
  60. package/dist/tools/json-query.js.map +0 -1
  61. package/dist/tools/text-transform.d.ts +0 -16
  62. package/dist/tools/text-transform.d.ts.map +0 -1
  63. package/dist/tools/text-transform.js +0 -127
  64. package/dist/tools/text-transform.js.map +0 -1
  65. package/dist/tools/wait.d.ts +0 -6
  66. package/dist/tools/wait.d.ts.map +0 -1
  67. package/dist/tools/wait.js +0 -32
  68. package/dist/tools/wait.js.map +0 -1
  69. package/dist/types.d.ts +0 -4
  70. package/dist/types.d.ts.map +0 -1
  71. package/dist/types.js +0 -6
  72. package/dist/types.js.map +0 -1
  73. package/dist/utils.d.ts +0 -17
  74. package/dist/utils.d.ts.map +0 -1
  75. package/dist/utils.js +0 -159
  76. package/dist/utils.js.map +0 -1
  77. package/src/__tests__/basic-system-prompt.test.ts +0 -186
  78. package/src/__tests__/compaction-summarize.test.ts +0 -282
  79. package/src/__tests__/logging.test.ts +0 -200
  80. package/src/__tests__/message-window.test.ts +0 -194
  81. package/src/__tests__/required-tools-guard.test.ts +0 -207
  82. package/src/__tests__/tool-search.test.ts +0 -187
  83. package/src/__tests__/tools.test.ts +0 -332
  84. package/src/extensions/basic-system-prompt.ts +0 -48
  85. package/src/extensions/compaction-summarize.ts +0 -104
  86. package/src/extensions/logging.ts +0 -42
  87. package/src/extensions/message-window.ts +0 -23
  88. package/src/extensions/required-tools-guard.ts +0 -24
  89. package/src/extensions/tool-search.ts +0 -38
  90. package/src/index.ts +0 -16
  91. package/src/tools/bash.ts +0 -38
  92. package/src/tools/file-system.ts +0 -83
  93. package/src/tools/http-fetch.ts +0 -64
  94. package/src/tools/json-query.ts +0 -71
  95. package/src/tools/text-transform.ts +0 -59
  96. package/src/tools/wait.ts +0 -46
  97. package/tsconfig.json +0 -8
  98. package/vitest.config.ts +0 -7
package/package.json CHANGED
@@ -1,26 +1,31 @@
1
1
  {
2
2
  "name": "@goondan/openharness-base",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
+ "types": "./dist/index.d.ts",
5
6
  "exports": {
6
7
  ".": {
7
8
  "import": "./dist/index.js",
8
9
  "types": "./dist/index.d.ts"
9
10
  }
10
11
  },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsup src/index.ts --format esm --dts",
17
+ "prepack": "pnpm build",
18
+ "test": "vitest run",
19
+ "typecheck": "tsc --noEmit",
20
+ "clean": "rm -rf dist"
21
+ },
11
22
  "dependencies": {
12
- "@goondan/openharness-types": "0.1.7"
23
+ "@goondan/openharness-types": "workspace:*"
13
24
  },
14
25
  "devDependencies": {
15
26
  "@types/node": "^25.5.0",
16
27
  "tsup": "^8.4.0",
17
28
  "typescript": "^5.7.0",
18
29
  "vitest": "^3.0.0"
19
- },
20
- "scripts": {
21
- "build": "tsup src/index.ts --format esm --dts",
22
- "test": "vitest run",
23
- "typecheck": "tsc --noEmit",
24
- "clean": "rm -rf dist"
25
30
  }
26
- }
31
+ }
@@ -1,12 +0,0 @@
1
- import type { ExtensionApi } from '../types.js';
2
- export interface CompactionExtensionConfig {
3
- maxMessages?: number;
4
- maxCharacters?: number;
5
- retainLastMessages?: number;
6
- mode?: 'remove' | 'truncate';
7
- appendSummary?: boolean;
8
- summaryPrefix?: string;
9
- }
10
- export declare function registerCompactionExtension(api: ExtensionApi, config?: CompactionExtensionConfig): void;
11
- export declare function register(api: ExtensionApi, config?: CompactionExtensionConfig): void;
12
- //# sourceMappingURL=compaction.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/extensions/compaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAIb,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,IAAI,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAqKD,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,YAAY,EACjB,MAAM,CAAC,EAAE,yBAAyB,GACjC,IAAI,CA6BN;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAEpF"}
@@ -1,159 +0,0 @@
1
- import { createId, estimateMessageLength } from '../utils.js';
2
- import { normalizeRemovalTargets } from './message-integrity.js';
3
- const DEFAULT_CONFIG = {
4
- maxMessages: 40,
5
- maxCharacters: 12_000,
6
- retainLastMessages: 8,
7
- mode: 'remove',
8
- appendSummary: true,
9
- summaryPrefix: '[message-compaction]',
10
- };
11
- function isPinned(message) {
12
- return message.metadata.pinned === true;
13
- }
14
- function createSummaryMessage(config, result) {
15
- const summaryText = `${config.summaryPrefix} mode=${result.mode} removed=${result.removedCount} chars=${result.removedCharacters}`;
16
- return {
17
- id: createId('msg'),
18
- data: {
19
- role: 'user',
20
- content: summaryText,
21
- },
22
- metadata: {
23
- __createdBy: 'message-compaction',
24
- 'compaction.summary': true,
25
- 'compaction.mode': result.mode,
26
- 'compaction.removedCount': result.removedCount,
27
- 'compaction.removedCharacters': result.removedCharacters,
28
- },
29
- createdAt: new Date(),
30
- };
31
- }
32
- function emitEvents(ctx, events) {
33
- for (const event of events) {
34
- ctx.emitMessageEvent(event);
35
- }
36
- }
37
- function compactByRemoval(messages, config) {
38
- const candidateRemovedIds = new Set();
39
- const protectedIds = new Set();
40
- const keepFrom = Math.max(0, messages.length - config.retainLastMessages);
41
- for (let index = keepFrom; index < messages.length; index += 1) {
42
- const protectedMessage = messages[index];
43
- if (!protectedMessage) {
44
- continue;
45
- }
46
- protectedIds.add(protectedMessage.id);
47
- }
48
- let remainingCount = messages.length;
49
- let remainingCharacters = messages.reduce((sum, message) => sum + estimateMessageLength(message), 0);
50
- for (const message of messages) {
51
- const overMessageLimit = remainingCount > config.maxMessages;
52
- const overCharacterLimit = remainingCharacters > config.maxCharacters;
53
- if (!overMessageLimit && !overCharacterLimit) {
54
- break;
55
- }
56
- if (protectedIds.has(message.id) || isPinned(message)) {
57
- continue;
58
- }
59
- const messageSize = estimateMessageLength(message);
60
- remainingCount -= 1;
61
- remainingCharacters -= messageSize;
62
- candidateRemovedIds.add(message.id);
63
- }
64
- const finalRemovedIds = normalizeRemovalTargets(messages, candidateRemovedIds);
65
- const events = [];
66
- let finalRemainingCount = 0;
67
- let finalRemainingCharacters = 0;
68
- let finalRemovedCount = 0;
69
- let finalRemovedCharacters = 0;
70
- for (const message of messages) {
71
- const messageSize = estimateMessageLength(message);
72
- if (finalRemovedIds.has(message.id)) {
73
- finalRemovedCount += 1;
74
- finalRemovedCharacters += messageSize;
75
- events.push({
76
- type: 'remove',
77
- targetId: message.id,
78
- });
79
- continue;
80
- }
81
- finalRemainingCount += 1;
82
- finalRemainingCharacters += messageSize;
83
- }
84
- const overflow = finalRemainingCount > config.maxMessages || finalRemainingCharacters > config.maxCharacters;
85
- return {
86
- events,
87
- result: {
88
- mode: 'remove',
89
- removedCount: finalRemovedCount,
90
- removedCharacters: finalRemovedCharacters,
91
- },
92
- overflow,
93
- };
94
- }
95
- function compactByTruncate() {
96
- return {
97
- events: [{ type: 'truncate' }],
98
- result: {
99
- mode: 'truncate',
100
- removedCount: 0,
101
- removedCharacters: 0,
102
- },
103
- };
104
- }
105
- function shouldCompact(messages, config) {
106
- if (messages.length > config.maxMessages) {
107
- return true;
108
- }
109
- const totalCharacters = messages.reduce((sum, message) => sum + estimateMessageLength(message), 0);
110
- return totalCharacters > config.maxCharacters;
111
- }
112
- function mergeConfig(config) {
113
- return {
114
- maxMessages: config?.maxMessages ?? DEFAULT_CONFIG.maxMessages,
115
- maxCharacters: config?.maxCharacters ?? DEFAULT_CONFIG.maxCharacters,
116
- retainLastMessages: config?.retainLastMessages ?? DEFAULT_CONFIG.retainLastMessages,
117
- mode: config?.mode ?? DEFAULT_CONFIG.mode,
118
- appendSummary: config?.appendSummary ?? DEFAULT_CONFIG.appendSummary,
119
- summaryPrefix: config?.summaryPrefix ?? DEFAULT_CONFIG.summaryPrefix,
120
- };
121
- }
122
- function maybeAppendSummary(events, config, result) {
123
- if (!config.appendSummary) {
124
- return;
125
- }
126
- events.push({
127
- type: 'append',
128
- message: createSummaryMessage(config, result),
129
- });
130
- }
131
- export function registerCompactionExtension(api, config) {
132
- const settings = mergeConfig(config);
133
- api.pipeline.register('turn', async (ctx) => {
134
- const messages = ctx.conversationState.nextMessages;
135
- if (!shouldCompact(messages, settings)) {
136
- return ctx.next();
137
- }
138
- if (settings.mode === 'truncate') {
139
- const { events, result } = compactByTruncate();
140
- maybeAppendSummary(events, settings, result);
141
- emitEvents(ctx, events);
142
- return ctx.next();
143
- }
144
- const removal = compactByRemoval(messages, settings);
145
- if (removal.overflow) {
146
- const truncate = compactByTruncate();
147
- maybeAppendSummary(truncate.events, settings, truncate.result);
148
- emitEvents(ctx, truncate.events);
149
- return ctx.next();
150
- }
151
- maybeAppendSummary(removal.events, settings, removal.result);
152
- emitEvents(ctx, removal.events);
153
- return ctx.next();
154
- });
155
- }
156
- export function register(api, config) {
157
- registerCompactionExtension(api, config);
158
- }
159
- //# sourceMappingURL=compaction.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"compaction.js","sourceRoot":"","sources":["../../src/extensions/compaction.ts"],"names":[],"mappings":"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"}
@@ -1,9 +0,0 @@
1
- import type { ExtensionApi } from '../types.js';
2
- export interface ContextMessageExtensionConfig {
3
- includeAgentPrompt?: boolean;
4
- includeInboundContext?: boolean;
5
- includeRouteSummary?: boolean;
6
- includeInboundInput?: boolean;
7
- }
8
- export declare function register(api: ExtensionApi, rawConfig?: unknown): void;
9
- //# sourceMappingURL=context-message.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-message.d.ts","sourceRoot":"","sources":["../../src/extensions/context-message.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAA6E,MAAM,aAAa,CAAC;AAmC3H,MAAM,WAAW,6BAA6B;IAC5C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AA6hBD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAOrE"}
@@ -1,446 +0,0 @@
1
- import { createHash } from 'node:crypto';
2
- import { createId, isJsonObject } from '../utils.js';
3
- const EXTENSION_NAME = 'context-message';
4
- const EXTENSION_EVENTS_METADATA_KEY = 'extension.events';
5
- const CONTEXT_MESSAGE_MARKER_KEY = '__goondanContextMessage';
6
- const INBOUND_MESSAGE_METADATA_KEY = '__goondanInbound';
7
- const DEFAULT_CONFIG = {
8
- includeAgentPrompt: true,
9
- includeInboundContext: false,
10
- includeRouteSummary: false,
11
- includeInboundInput: true,
12
- };
13
- function readConfig(raw) {
14
- if (!isJsonObject(raw)) {
15
- return { ...DEFAULT_CONFIG };
16
- }
17
- const config = { ...DEFAULT_CONFIG };
18
- if (typeof raw.includeAgentPrompt === 'boolean') {
19
- config.includeAgentPrompt = raw.includeAgentPrompt;
20
- }
21
- if (typeof raw.includeInboundContext === 'boolean') {
22
- config.includeInboundContext = raw.includeInboundContext;
23
- }
24
- if (typeof raw.includeRouteSummary === 'boolean') {
25
- config.includeRouteSummary = raw.includeRouteSummary;
26
- }
27
- if (typeof raw.includeInboundInput === 'boolean') {
28
- config.includeInboundInput = raw.includeInboundInput;
29
- }
30
- return config;
31
- }
32
- function createPromptHash(input) {
33
- return createHash('sha256').update(`${input.role}\n${input.content}`).digest('hex');
34
- }
35
- function readPromptHashMarker(message) {
36
- const marker = readContextMessageMarker(message);
37
- return marker?.promptHash;
38
- }
39
- function readContextMessageMarker(message) {
40
- if (!isJsonObject(message.metadata)) {
41
- return undefined;
42
- }
43
- const rawMarker = message.metadata[CONTEXT_MESSAGE_MARKER_KEY];
44
- if (!isJsonObject(rawMarker)) {
45
- return undefined;
46
- }
47
- const promptHash = rawMarker.promptHash;
48
- if (typeof promptHash !== 'string' || promptHash.length === 0) {
49
- return undefined;
50
- }
51
- const marker = {
52
- promptHash,
53
- };
54
- if (rawMarker.role === 'system' || rawMarker.role === 'user') {
55
- marker.role = rawMarker.role;
56
- }
57
- if (Array.isArray(rawMarker.segmentIds)) {
58
- marker.segmentIds = rawMarker.segmentIds
59
- .filter((segmentId) => typeof segmentId === 'string' && segmentId.length > 0);
60
- }
61
- return marker;
62
- }
63
- function markerIncludesSegment(marker, segmentId) {
64
- if (!marker || !Array.isArray(marker.segmentIds)) {
65
- return false;
66
- }
67
- return marker.segmentIds.includes(segmentId);
68
- }
69
- function hasPromptHashMarker(messages, promptHash, role, content) {
70
- for (const message of messages) {
71
- const existingHash = readPromptHashMarker(message);
72
- if (existingHash === promptHash) {
73
- return true;
74
- }
75
- if (message.metadata.__createdBy === EXTENSION_NAME
76
- && message.data.role === role
77
- && message.data.content === content) {
78
- return true;
79
- }
80
- }
81
- return false;
82
- }
83
- function createMessageMarker(promptHash, role, segmentIds) {
84
- const marker = {
85
- promptHash,
86
- role,
87
- segmentIds,
88
- };
89
- return marker;
90
- }
91
- function createContextMessage(promptHash, role, content, segmentIds) {
92
- const metadata = {
93
- [CONTEXT_MESSAGE_MARKER_KEY]: createMessageMarker(promptHash, role, segmentIds),
94
- };
95
- if (role === 'system') {
96
- metadata.pinned = true;
97
- }
98
- metadata.__createdBy = EXTENSION_NAME;
99
- return {
100
- id: createId('msg'),
101
- data: {
102
- role,
103
- content,
104
- },
105
- metadata,
106
- createdAt: new Date(),
107
- };
108
- }
109
- function createInboundInputMetadata(ctx) {
110
- const inbound = ctx.runtime.inbound;
111
- const payload = {
112
- sourceKind: inbound.kind,
113
- sourceName: inbound.sourceName,
114
- eventName: inbound.eventType,
115
- };
116
- if (typeof inbound.connectionName === 'string' && inbound.connectionName.length > 0) {
117
- payload.connectionName = inbound.connectionName;
118
- }
119
- if (typeof inbound.conversationId === 'string' && inbound.conversationId.length > 0) {
120
- payload.conversationId = inbound.conversationId;
121
- }
122
- if (inbound.kind === 'connector') {
123
- if (Object.keys(inbound.properties).length > 0) {
124
- payload.properties = inbound.properties;
125
- }
126
- if (ctx.inputEvent.rawPayload !== undefined) {
127
- payload.rawPayload = ctx.inputEvent.rawPayload;
128
- }
129
- }
130
- return {
131
- [INBOUND_MESSAGE_METADATA_KEY]: payload,
132
- };
133
- }
134
- function createInboundInputMessage(ctx, content) {
135
- const metadata = createInboundInputMetadata(ctx);
136
- metadata.__createdBy = EXTENSION_NAME;
137
- return {
138
- id: createId('msg'),
139
- data: {
140
- role: 'user',
141
- content,
142
- },
143
- metadata,
144
- createdAt: new Date(),
145
- };
146
- }
147
- function renderInboundParts(parts) {
148
- const textBlocks = [];
149
- const attachmentBlocks = [];
150
- for (const part of parts) {
151
- if (part.type === 'text') {
152
- const trimmed = part.text.trim();
153
- if (trimmed.length > 0) {
154
- textBlocks.push(trimmed);
155
- }
156
- continue;
157
- }
158
- if (part.type === 'image') {
159
- const label = typeof part.alt === 'string' && part.alt.trim().length > 0 ? ` ${part.alt.trim()}` : '';
160
- attachmentBlocks.push(`[image]${label} ${part.url}`.trim());
161
- continue;
162
- }
163
- const mimeLabel = typeof part.mimeType === 'string' && part.mimeType.trim().length > 0
164
- ? ` (${part.mimeType.trim()})`
165
- : '';
166
- attachmentBlocks.push(`[file] ${part.name}${mimeLabel}: ${part.url}`);
167
- }
168
- return [...textBlocks, ...attachmentBlocks].join('\n\n').trim();
169
- }
170
- function appendRuntimeEvent(ctx, name, data = undefined) {
171
- const entries = Array.isArray(ctx.metadata[EXTENSION_EVENTS_METADATA_KEY])
172
- ? [...ctx.metadata[EXTENSION_EVENTS_METADATA_KEY]]
173
- : [];
174
- const entry = {
175
- name,
176
- actor: EXTENSION_NAME,
177
- at: new Date().toISOString(),
178
- };
179
- if (data !== undefined && Object.keys(data).length > 0) {
180
- entry.data = data;
181
- }
182
- entries.push(entry);
183
- ctx.metadata[EXTENSION_EVENTS_METADATA_KEY] = entries;
184
- }
185
- function resolveAgentPrompt(metadata) {
186
- const prompt = metadata.prompt;
187
- if (!prompt) {
188
- return null;
189
- }
190
- const inlinePrompt = typeof prompt.system === 'string' && prompt.system.trim().length > 0
191
- ? prompt.system
192
- : undefined;
193
- if (!inlinePrompt) {
194
- return null;
195
- }
196
- return inlinePrompt;
197
- }
198
- function stringOrUndefined(value) {
199
- if (typeof value !== 'string') {
200
- return undefined;
201
- }
202
- const trimmed = value.trim();
203
- if (trimmed.length === 0) {
204
- return undefined;
205
- }
206
- return trimmed;
207
- }
208
- function resolveInboundContextSegment(ctx) {
209
- const inbound = ctx.runtime.inbound;
210
- const lines = [
211
- '[runtime_inbound]',
212
- `eventId=${inbound.eventId}`,
213
- `eventType=${inbound.eventType}`,
214
- `kind=${inbound.kind}`,
215
- `sourceName=${inbound.sourceName}`,
216
- `createdAt=${inbound.createdAt}`,
217
- ];
218
- if (typeof inbound.connectionName === 'string' && inbound.connectionName.length > 0) {
219
- lines.push(`connectionName=${inbound.connectionName}`);
220
- }
221
- if (typeof inbound.conversationId === 'string' && inbound.conversationId.length > 0) {
222
- lines.push(`conversationId=${inbound.conversationId}`);
223
- }
224
- if (Object.keys(inbound.properties).length > 0) {
225
- lines.push(`properties=${JSON.stringify(inbound.properties)}`);
226
- }
227
- if (inbound.content.length > 0) {
228
- lines.push(`content=${JSON.stringify(inbound.content)}`);
229
- }
230
- if (inbound.rawPayload !== undefined) {
231
- lines.push(`rawPayload=${JSON.stringify(inbound.rawPayload)}`);
232
- }
233
- lines.push('[/runtime_inbound]');
234
- return {
235
- id: 'runtime.inbound',
236
- role: 'user',
237
- content: lines.join('\n'),
238
- };
239
- }
240
- function resolveRouteSummarySegment(ctx) {
241
- const inbound = ctx.runtime.inbound;
242
- const inboundConversationId = stringOrUndefined(inbound.conversationId);
243
- const lines = [
244
- '[runtime_route]',
245
- 'precedence=inbound',
246
- `senderKind=${inbound.kind}`,
247
- `senderName=${inbound.sourceName}`,
248
- `eventType=${inbound.eventType}`,
249
- `eventId=${inbound.eventId}`,
250
- ];
251
- if (inboundConversationId) {
252
- lines.push(`senderConversationId=${inboundConversationId}`);
253
- }
254
- lines.push('[/runtime_route]');
255
- return {
256
- id: 'runtime.route.summary',
257
- role: 'user',
258
- content: lines.join('\n'),
259
- };
260
- }
261
- const SEGMENT_ORDER = [
262
- 'agent.prompt.system',
263
- 'runtime.inbound',
264
- 'runtime.route.summary',
265
- ];
266
- function sortSegmentsByOrder(segments) {
267
- const order = new Map();
268
- SEGMENT_ORDER.forEach((id, index) => {
269
- order.set(id, index);
270
- });
271
- return [...segments].sort((left, right) => {
272
- const leftOrder = order.get(left.id) ?? Number.MAX_SAFE_INTEGER;
273
- const rightOrder = order.get(right.id) ?? Number.MAX_SAFE_INTEGER;
274
- if (leftOrder !== rightOrder) {
275
- return leftOrder - rightOrder;
276
- }
277
- return left.id.localeCompare(right.id);
278
- });
279
- }
280
- function resolveContextSegments(ctx, config) {
281
- const resolutions = [];
282
- const segments = [];
283
- if (config.includeAgentPrompt) {
284
- const system = resolveAgentPrompt({ prompt: ctx.runtime.agent.prompt });
285
- if (system && system.trim().length > 0) {
286
- segments.push({
287
- id: 'agent.prompt.system',
288
- role: 'system',
289
- content: system,
290
- });
291
- resolutions.push({ id: 'agent.prompt.system', included: true });
292
- }
293
- else {
294
- resolutions.push({ id: 'agent.prompt.system', included: false });
295
- }
296
- }
297
- if (config.includeInboundContext) {
298
- segments.push(resolveInboundContextSegment(ctx));
299
- resolutions.push({ id: 'runtime.inbound', included: true });
300
- }
301
- if (config.includeRouteSummary && config.includeInboundContext) {
302
- segments.push(resolveRouteSummarySegment(ctx));
303
- resolutions.push({ id: 'runtime.route.summary', included: true });
304
- }
305
- return {
306
- resolutions,
307
- segments: sortSegmentsByOrder(segments),
308
- };
309
- }
310
- function composeMessageGroups(segments) {
311
- const groups = [];
312
- for (const segment of segments) {
313
- const last = groups[groups.length - 1];
314
- if (last && last.role === segment.role) {
315
- last.content = `${last.content}\n\n${segment.content}`;
316
- last.segmentIds.push(segment.id);
317
- continue;
318
- }
319
- groups.push({
320
- role: segment.role,
321
- content: segment.content,
322
- segmentIds: [segment.id],
323
- });
324
- }
325
- return groups;
326
- }
327
- async function emitContextMessages(ctx, config) {
328
- const composed = resolveContextSegments(ctx, config);
329
- for (const resolution of composed.resolutions) {
330
- appendRuntimeEvent(ctx, 'context.segment.resolved', {
331
- id: resolution.id,
332
- included: resolution.included,
333
- });
334
- }
335
- if (composed.segments.length === 0) {
336
- appendRuntimeEvent(ctx, 'context.message.empty');
337
- return;
338
- }
339
- const existingMessages = ctx.conversationState.nextMessages;
340
- const groups = composeMessageGroups(composed.segments);
341
- const desiredSystemGroup = groups.find((group) => group.role === 'system' && group.segmentIds.includes('agent.prompt.system'));
342
- const desiredSystemHash = desiredSystemGroup
343
- ? createPromptHash({ role: desiredSystemGroup.role, content: desiredSystemGroup.content })
344
- : undefined;
345
- const pendingGroups = [];
346
- for (const group of groups) {
347
- const promptHash = createPromptHash({ role: group.role, content: group.content });
348
- if (hasPromptHashMarker(existingMessages, promptHash, group.role, group.content)) {
349
- appendRuntimeEvent(ctx, 'context.message.duplicate', {
350
- promptHash,
351
- role: group.role,
352
- });
353
- continue;
354
- }
355
- pendingGroups.push({ group, promptHash });
356
- }
357
- let emittedContextMutation = false;
358
- if (desiredSystemGroup && desiredSystemHash) {
359
- const existingSystems = existingMessages
360
- .filter((message) => message.data.role === 'system')
361
- .map((message) => ({
362
- message,
363
- marker: readContextMessageMarker(message),
364
- }));
365
- if (existingSystems.length > 0) {
366
- const preferred = existingSystems.find((entry) => entry.marker?.promptHash === desiredSystemHash)
367
- ?? existingSystems.find((entry) => markerIncludesSegment(entry.marker, 'agent.prompt.system'))
368
- ?? existingSystems[0];
369
- if (preferred) {
370
- const targetMessage = preferred.message;
371
- const targetMarker = preferred.marker;
372
- const targetMatchesDesired = targetMarker?.promptHash === desiredSystemHash
373
- || targetMessage.data.content === desiredSystemGroup.content;
374
- if (!targetMatchesDesired) {
375
- ctx.emitMessageEvent({
376
- type: 'replace',
377
- targetId: targetMessage.id,
378
- message: createContextMessage(desiredSystemHash, 'system', desiredSystemGroup.content, desiredSystemGroup.segmentIds),
379
- });
380
- appendRuntimeEvent(ctx, 'context.message.replaced', {
381
- targetId: targetMessage.id,
382
- promptHash: desiredSystemHash,
383
- role: 'system',
384
- segmentIds: desiredSystemGroup.segmentIds,
385
- });
386
- emittedContextMutation = true;
387
- }
388
- for (const entry of existingSystems) {
389
- if (entry.message.id === targetMessage.id) {
390
- continue;
391
- }
392
- ctx.emitMessageEvent({
393
- type: 'remove',
394
- targetId: entry.message.id,
395
- });
396
- appendRuntimeEvent(ctx, 'context.message.removed', {
397
- targetId: entry.message.id,
398
- role: 'system',
399
- });
400
- emittedContextMutation = true;
401
- }
402
- const duplicateSystemIndex = pendingGroups.findIndex((pending) => pending.group.role === 'system' && pending.group.segmentIds.includes('agent.prompt.system'));
403
- if (duplicateSystemIndex >= 0) {
404
- pendingGroups.splice(duplicateSystemIndex, 1);
405
- }
406
- }
407
- }
408
- }
409
- for (const pending of pendingGroups) {
410
- const group = pending.group;
411
- ctx.emitMessageEvent({
412
- type: 'append',
413
- message: createContextMessage(pending.promptHash, group.role, group.content, group.segmentIds),
414
- });
415
- appendRuntimeEvent(ctx, 'context.message.appended', {
416
- promptHash: pending.promptHash,
417
- role: group.role,
418
- segmentIds: group.segmentIds,
419
- });
420
- emittedContextMutation = true;
421
- }
422
- const renderedInboundInput = ctx.runtime.inbound.kind === 'connector'
423
- ? renderInboundParts(ctx.runtime.inbound.content)
424
- : '';
425
- const inboundInput = renderedInboundInput.trim().length > 0
426
- ? renderedInboundInput
427
- : (typeof ctx.inputEvent.input === 'string' ? ctx.inputEvent.input : '');
428
- if (config.includeInboundInput && inboundInput.trim().length > 0) {
429
- ctx.emitMessageEvent({
430
- type: 'append',
431
- message: createInboundInputMessage(ctx, inboundInput),
432
- });
433
- appendRuntimeEvent(ctx, 'context.inbound.appended');
434
- }
435
- if (!emittedContextMutation) {
436
- appendRuntimeEvent(ctx, 'context.message.empty');
437
- }
438
- }
439
- export function register(api, rawConfig) {
440
- const config = readConfig(rawConfig);
441
- api.pipeline.register('turn', async (ctx) => {
442
- await emitContextMessages(ctx, config);
443
- return ctx.next();
444
- });
445
- }
446
- //# sourceMappingURL=context-message.js.map