@goondan/openharness-base 0.1.6 → 0.1.8

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 (78) hide show
  1. package/package.json +9 -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 +0 -84
  32. package/dist/index.d.ts.map +0 -1
  33. package/dist/index.js +0 -537
  34. package/dist/index.js.map +0 -1
  35. package/dist/manifests/base.d.ts +0 -8
  36. package/dist/manifests/base.d.ts.map +0 -1
  37. package/dist/manifests/base.js +0 -352
  38. package/dist/manifests/base.js.map +0 -1
  39. package/dist/manifests/index.d.ts +0 -3
  40. package/dist/manifests/index.d.ts.map +0 -1
  41. package/dist/manifests/index.js +0 -2
  42. package/dist/manifests/index.js.map +0 -1
  43. package/dist/tools/bash.d.ts +0 -8
  44. package/dist/tools/bash.d.ts.map +0 -1
  45. package/dist/tools/bash.js +0 -119
  46. package/dist/tools/bash.js.map +0 -1
  47. package/dist/tools/file-system.d.ts +0 -12
  48. package/dist/tools/file-system.d.ts.map +0 -1
  49. package/dist/tools/file-system.js +0 -117
  50. package/dist/tools/file-system.js.map +0 -1
  51. package/dist/tools/http-fetch.d.ts +0 -8
  52. package/dist/tools/http-fetch.d.ts.map +0 -1
  53. package/dist/tools/http-fetch.js +0 -149
  54. package/dist/tools/http-fetch.js.map +0 -1
  55. package/dist/tools/index.d.ts +0 -7
  56. package/dist/tools/index.d.ts.map +0 -1
  57. package/dist/tools/index.js +0 -7
  58. package/dist/tools/index.js.map +0 -1
  59. package/dist/tools/json-query.d.ts +0 -12
  60. package/dist/tools/json-query.d.ts.map +0 -1
  61. package/dist/tools/json-query.js +0 -176
  62. package/dist/tools/json-query.js.map +0 -1
  63. package/dist/tools/text-transform.d.ts +0 -16
  64. package/dist/tools/text-transform.d.ts.map +0 -1
  65. package/dist/tools/text-transform.js +0 -127
  66. package/dist/tools/text-transform.js.map +0 -1
  67. package/dist/tools/wait.d.ts +0 -6
  68. package/dist/tools/wait.d.ts.map +0 -1
  69. package/dist/tools/wait.js +0 -32
  70. package/dist/tools/wait.js.map +0 -1
  71. package/dist/types.d.ts +0 -4
  72. package/dist/types.d.ts.map +0 -1
  73. package/dist/types.js +0 -6
  74. package/dist/types.js.map +0 -1
  75. package/dist/utils.d.ts +0 -17
  76. package/dist/utils.d.ts.map +0 -1
  77. package/dist/utils.js +0 -159
  78. package/dist/utils.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goondan/openharness-base",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -8,19 +8,19 @@
8
8
  "types": "./dist/index.d.ts"
9
9
  }
10
10
  },
11
- "scripts": {
12
- "build": "tsup src/index.ts --format esm --dts",
13
- "test": "vitest run",
14
- "typecheck": "tsc --noEmit",
15
- "clean": "rm -rf dist"
16
- },
17
11
  "dependencies": {
18
- "@goondan/openharness-types": "workspace:*"
12
+ "@goondan/openharness-types": "0.1.8"
19
13
  },
20
14
  "devDependencies": {
21
15
  "@types/node": "^25.5.0",
22
16
  "tsup": "^8.4.0",
23
17
  "typescript": "^5.7.0",
24
18
  "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
25
  }
26
- }
26
+ }
@@ -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