@workbench-ai/agent-driver 0.0.44

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 (52) hide show
  1. package/dist/access-contracts.d.ts +10 -0
  2. package/dist/access-contracts.d.ts.map +1 -0
  3. package/dist/access-contracts.js +45 -0
  4. package/dist/behavior-contract.d.ts +26 -0
  5. package/dist/behavior-contract.d.ts.map +1 -0
  6. package/dist/behavior-contract.js +200 -0
  7. package/dist/conformance.d.ts +3 -0
  8. package/dist/conformance.d.ts.map +1 -0
  9. package/dist/conformance.js +37 -0
  10. package/dist/global-skills.d.ts +22 -0
  11. package/dist/global-skills.d.ts.map +1 -0
  12. package/dist/global-skills.js +168 -0
  13. package/dist/index.d.ts +138 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +44 -0
  16. package/dist/internal-utils.d.ts +8 -0
  17. package/dist/internal-utils.d.ts.map +1 -0
  18. package/dist/internal-utils.js +46 -0
  19. package/dist/json-rpc.d.ts +22 -0
  20. package/dist/json-rpc.d.ts.map +1 -0
  21. package/dist/json-rpc.js +1 -0
  22. package/dist/managed-runtime.d.ts +21 -0
  23. package/dist/managed-runtime.d.ts.map +1 -0
  24. package/dist/managed-runtime.js +119 -0
  25. package/dist/model-config.d.ts +17 -0
  26. package/dist/model-config.d.ts.map +1 -0
  27. package/dist/model-config.js +43 -0
  28. package/dist/normalized-activity.d.ts +75 -0
  29. package/dist/normalized-activity.d.ts.map +1 -0
  30. package/dist/normalized-activity.js +89 -0
  31. package/dist/prepare.d.ts +9 -0
  32. package/dist/prepare.d.ts.map +1 -0
  33. package/dist/prepare.js +119 -0
  34. package/dist/process-env.d.ts +20 -0
  35. package/dist/process-env.d.ts.map +1 -0
  36. package/dist/process-env.js +75 -0
  37. package/dist/session-runtime.d.ts +60 -0
  38. package/dist/session-runtime.d.ts.map +1 -0
  39. package/dist/session-runtime.js +240 -0
  40. package/dist/tool-semantics.d.ts +22 -0
  41. package/dist/tool-semantics.d.ts.map +1 -0
  42. package/dist/tool-semantics.js +241 -0
  43. package/dist/trace-builder.d.ts +88 -0
  44. package/dist/trace-builder.d.ts.map +1 -0
  45. package/dist/trace-builder.js +493 -0
  46. package/dist/trace-replay.d.ts +33 -0
  47. package/dist/trace-replay.d.ts.map +1 -0
  48. package/dist/trace-replay.js +4 -0
  49. package/dist/types.d.ts +156 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +10 -0
  52. package/package.json +39 -0
@@ -0,0 +1,20 @@
1
+ export interface ResolvedRuntimeEnv {
2
+ name: string;
3
+ value: string | undefined;
4
+ source: "repo_env" | "home_env" | "process_env" | "missing";
5
+ envPath: string | null;
6
+ explicitly_set: boolean;
7
+ blank: boolean;
8
+ }
9
+ export interface RuntimeEnvOptions {
10
+ runtimeHome?: string;
11
+ parentEnv?: NodeJS.ProcessEnv;
12
+ }
13
+ type RuntimeEnvResolutionSource = Exclude<ResolvedRuntimeEnv["source"], "missing">;
14
+ export declare function getRuntimeEnvPath(rootPath: string): string;
15
+ export declare function getRuntimeEnv(name: string, repoRoot: string, options?: RuntimeEnvOptions): string | undefined;
16
+ export declare function resolveRuntimeEnvWithPrecedence(name: string, repoRoot: string, precedence: readonly RuntimeEnvResolutionSource[], options?: RuntimeEnvOptions): ResolvedRuntimeEnv;
17
+ export declare function resolveRuntimeEnv(name: string, repoRoot: string, options?: RuntimeEnvOptions): ResolvedRuntimeEnv;
18
+ export declare function resetRuntimeEnvForTests(): void;
19
+ export {};
20
+ //# sourceMappingURL=process-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-env.d.ts","sourceRoot":"","sources":["../src/process-env.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC;IAC5D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAED,KAAK,0BAA0B,GAAG,OAAO,CACvC,kBAAkB,CAAC,QAAQ,CAAC,EAC5B,SAAS,CACV,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AA4CD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,iBAAsB,GAC9B,MAAM,GAAG,SAAS,CAEpB;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,SAAS,0BAA0B,EAAE,EACjD,OAAO,GAAE,iBAAsB,GAC9B,kBAAkB,CA2CpB;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,iBAAsB,GAC9B,kBAAkB,CAOpB;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C"}
@@ -0,0 +1,75 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { parseEnv } from "node:util";
4
+ import { resolveRuntimeHome } from "./internal-utils.js";
5
+ export function getRuntimeEnvPath(rootPath) {
6
+ return path.join(rootPath, ".env");
7
+ }
8
+ function readRuntimeEnvFile(repoRoot) {
9
+ const envPath = getRuntimeEnvPath(repoRoot);
10
+ if (!existsSync(envPath)) {
11
+ return {};
12
+ }
13
+ return parseEnv(readFileSync(envPath, "utf8"));
14
+ }
15
+ function collectRuntimeEnvFilesWithOptions(repoRoot, options) {
16
+ const normalizedRepoRoot = path.resolve(repoRoot);
17
+ const runtimeHome = resolveRuntimeHome(options.runtimeHome);
18
+ return {
19
+ repoValues: readRuntimeEnvFile(normalizedRepoRoot),
20
+ homeValues: readRuntimeEnvFile(runtimeHome),
21
+ runtimeHome,
22
+ };
23
+ }
24
+ function formatResolvedRuntimeEnv(name, source, value, envPath) {
25
+ return {
26
+ name,
27
+ value,
28
+ source,
29
+ envPath,
30
+ explicitly_set: true,
31
+ blank: !value?.trim(),
32
+ };
33
+ }
34
+ export function getRuntimeEnv(name, repoRoot, options = {}) {
35
+ return resolveRuntimeEnv(name, repoRoot, options).value;
36
+ }
37
+ export function resolveRuntimeEnvWithPrecedence(name, repoRoot, precedence, options = {}) {
38
+ const { repoValues, homeValues, runtimeHome } = collectRuntimeEnvFilesWithOptions(repoRoot, options);
39
+ const parentEnv = options.parentEnv ?? process.env;
40
+ const sourceValues = {
41
+ repo_env: {
42
+ envPath: getRuntimeEnvPath(repoRoot),
43
+ values: repoValues,
44
+ },
45
+ home_env: {
46
+ envPath: getRuntimeEnvPath(runtimeHome),
47
+ values: homeValues,
48
+ },
49
+ process_env: {
50
+ envPath: null,
51
+ values: parentEnv,
52
+ },
53
+ };
54
+ for (const source of precedence) {
55
+ const entry = sourceValues[source];
56
+ if (Object.prototype.hasOwnProperty.call(entry.values, name)) {
57
+ return formatResolvedRuntimeEnv(name, source, entry.values[name], entry.envPath);
58
+ }
59
+ }
60
+ return {
61
+ name,
62
+ value: undefined,
63
+ source: "missing",
64
+ envPath: null,
65
+ explicitly_set: false,
66
+ blank: false,
67
+ };
68
+ }
69
+ export function resolveRuntimeEnv(name, repoRoot, options = {}) {
70
+ return resolveRuntimeEnvWithPrecedence(name, repoRoot, ["repo_env", "home_env", "process_env"], options);
71
+ }
72
+ export function resetRuntimeEnvForTests() {
73
+ // Env resolution is intentionally stateless so repo-local edits are observed
74
+ // immediately.
75
+ }
@@ -0,0 +1,60 @@
1
+ import { type ChildProcessWithoutNullStreams } from "node:child_process";
2
+ import type { HarnessEvent, HarnessSession, JsonValue } from "./types.js";
3
+ import { type NormalizedHarnessActivity } from "./normalized-activity.js";
4
+ import { HarnessTraceBuilder } from "./trace-builder.js";
5
+ import type { HarnessRunResult, HarnessTurnLivePersistence } from "./index.js";
6
+ export interface PendingHarnessTurn {
7
+ controller: HarnessTurnController;
8
+ result: Promise<HarnessRunResult>;
9
+ resolve: (value: HarnessRunResult | Promise<HarnessRunResult>) => void;
10
+ reject: (error: Error) => void;
11
+ }
12
+ export declare function createHarnessSession(args: {
13
+ harnessId: string;
14
+ attemptNumber: number;
15
+ stageId: string;
16
+ stageRunIndex: number;
17
+ harnessSession?: Record<string, JsonValue>;
18
+ }): HarnessSession;
19
+ export declare class HarnessTurnController {
20
+ private readonly args;
21
+ readonly trace: HarnessTraceBuilder;
22
+ readonly events: HarnessEvent[];
23
+ private finalOutput;
24
+ private turnStartedRecorded;
25
+ private timeout;
26
+ private stallTimeout;
27
+ private flushTimer;
28
+ private flushChain;
29
+ private readonly pendingHarnessEvents;
30
+ constructor(args: {
31
+ session: HarnessSession;
32
+ eventsFile: string;
33
+ rawEventsFile: string;
34
+ stageSpanId: string;
35
+ promptText?: string | null;
36
+ turnTimeoutMs: number;
37
+ stallTimeoutMs: number;
38
+ onTimeout: (message: string) => void;
39
+ livePersistence?: HarnessTurnLivePersistence;
40
+ });
41
+ record(args: {
42
+ harnessEvent?: HarnessEvent | null;
43
+ rawEnvelope?: Record<string, unknown> | null;
44
+ normalized?: NormalizedHarnessActivity | NormalizedHarnessActivity[] | null;
45
+ }): void;
46
+ succeed(args?: {
47
+ endedAt?: string;
48
+ finalOutput?: string;
49
+ }): Promise<HarnessRunResult>;
50
+ dispose(): void;
51
+ flushNow(): Promise<void>;
52
+ private clearTimers;
53
+ private resetStallTimeout;
54
+ private scheduleFlush;
55
+ private trackOutput;
56
+ }
57
+ export declare function createPendingHarnessTurn(args: ConstructorParameters<typeof HarnessTurnController>[0]): PendingHarnessTurn;
58
+ export declare function terminateProcess(process: ChildProcessWithoutNullStreams, gracefulTimeoutMs: number, hardKillTimeoutMs: number): Promise<void>;
59
+ export declare function waitForProcessClose(process: ChildProcessWithoutNullStreams): Promise<void>;
60
+ //# sourceMappingURL=session-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-runtime.d.ts","sourceRoot":"","sources":["../src/session-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,240 @@
1
+ import { appendNdjson, createId, nowIso } from "./internal-utils.js";
2
+ import { applyNormalizedHarnessActivity, } from "./normalized-activity.js";
3
+ import { HarnessTraceBuilder } from "./trace-builder.js";
4
+ export function createHarnessSession(args) {
5
+ return {
6
+ id: createId("session"),
7
+ harness_id: args.harnessId,
8
+ attempt_number: args.attemptNumber,
9
+ stage_id: args.stageId,
10
+ stage_run_index: args.stageRunIndex,
11
+ harness_session: args.harnessSession ?? {},
12
+ started_at: nowIso(),
13
+ last_event_at: null,
14
+ };
15
+ }
16
+ export class HarnessTurnController {
17
+ args;
18
+ trace;
19
+ events = [];
20
+ finalOutput = "";
21
+ turnStartedRecorded = false;
22
+ timeout;
23
+ stallTimeout;
24
+ flushTimer = null;
25
+ flushChain = Promise.resolve();
26
+ pendingHarnessEvents = [];
27
+ constructor(args) {
28
+ this.args = args;
29
+ this.trace = new HarnessTraceBuilder({
30
+ attemptNumber: args.session.attempt_number,
31
+ stageId: args.session.stage_id,
32
+ stageRunIndex: args.session.stage_run_index,
33
+ stageSpanId: args.stageSpanId,
34
+ });
35
+ this.timeout = setTimeout(() => {
36
+ this.args.onTimeout(`turn timed out after ${this.args.turnTimeoutMs}ms`);
37
+ }, args.turnTimeoutMs);
38
+ this.stallTimeout = setTimeout(() => {
39
+ this.args.onTimeout(`turn stalled after ${this.args.stallTimeoutMs}ms`);
40
+ }, args.stallTimeoutMs);
41
+ }
42
+ record(args) {
43
+ if (args.rawEnvelope) {
44
+ void appendNdjson(this.args.rawEventsFile, args.rawEnvelope);
45
+ }
46
+ if (args.harnessEvent) {
47
+ void appendNdjson(this.args.eventsFile, args.harnessEvent);
48
+ this.events.push(args.harnessEvent);
49
+ this.pendingHarnessEvents.push(args.harnessEvent);
50
+ this.args.session.last_event_at = args.harnessEvent.at;
51
+ }
52
+ const normalized = args.normalized
53
+ ? Array.isArray(args.normalized)
54
+ ? args.normalized
55
+ : [args.normalized]
56
+ : [];
57
+ for (const activity of normalized) {
58
+ if (activity.type === "turn.started") {
59
+ if (this.turnStartedRecorded) {
60
+ continue;
61
+ }
62
+ this.turnStartedRecorded = true;
63
+ applyNormalizedHarnessActivity(this.trace, {
64
+ ...activity,
65
+ sessionId: activity.sessionId ?? this.args.session.id,
66
+ attributes: {
67
+ ...(activity.attributes ?? {}),
68
+ ...(this.args.promptText
69
+ ? {
70
+ prompt_text: this.args.promptText,
71
+ prompt_format: "text",
72
+ prompt_source: "rendered_stage_prompt",
73
+ }
74
+ : {}),
75
+ },
76
+ });
77
+ this.trackOutput(activity);
78
+ continue;
79
+ }
80
+ applyNormalizedHarnessActivity(this.trace, activity);
81
+ this.trackOutput(activity);
82
+ }
83
+ if (args.rawEnvelope || args.harnessEvent || normalized.length > 0) {
84
+ this.resetStallTimeout();
85
+ }
86
+ if (args.harnessEvent || normalized.length > 0) {
87
+ this.scheduleFlush();
88
+ }
89
+ }
90
+ async succeed(args) {
91
+ const finalOutput = (args?.finalOutput ?? this.finalOutput).trim();
92
+ const endedAt = args?.endedAt ?? nowIso();
93
+ const trace = {
94
+ trace_id: this.args.session.id,
95
+ ...this.trace.buildBundle(finalOutput, endedAt),
96
+ };
97
+ await this.flushNow();
98
+ this.clearTimers();
99
+ return {
100
+ sessionId: this.args.session.id,
101
+ finalOutput,
102
+ trace,
103
+ events: this.args.livePersistence?.onFlush ? [] : [...this.events],
104
+ };
105
+ }
106
+ dispose() {
107
+ void this.flushNow().catch(() => undefined);
108
+ this.clearTimers();
109
+ }
110
+ async flushNow() {
111
+ if (this.flushTimer) {
112
+ clearTimeout(this.flushTimer);
113
+ this.flushTimer = null;
114
+ }
115
+ if (!this.args.livePersistence?.onFlush) {
116
+ return;
117
+ }
118
+ const harnessEvents = [...this.pendingHarnessEvents];
119
+ this.pendingHarnessEvents.length = 0;
120
+ const traceBundle = this.trace.flushBundle();
121
+ if (harnessEvents.length === 0 &&
122
+ traceBundle.spans.length === 0 &&
123
+ traceBundle.events.length === 0 &&
124
+ traceBundle.summaries.length === 0) {
125
+ await this.flushChain;
126
+ return;
127
+ }
128
+ this.flushChain = this.flushChain
129
+ .catch(() => undefined)
130
+ .then(async () => {
131
+ await this.args.livePersistence?.onFlush({
132
+ harnessEvents,
133
+ traceBundle: traceBundle,
134
+ });
135
+ });
136
+ await this.flushChain;
137
+ }
138
+ clearTimers() {
139
+ if (this.timeout) {
140
+ clearTimeout(this.timeout);
141
+ this.timeout = null;
142
+ }
143
+ if (this.stallTimeout) {
144
+ clearTimeout(this.stallTimeout);
145
+ this.stallTimeout = null;
146
+ }
147
+ if (this.flushTimer) {
148
+ clearTimeout(this.flushTimer);
149
+ this.flushTimer = null;
150
+ }
151
+ }
152
+ resetStallTimeout() {
153
+ if (this.stallTimeout) {
154
+ clearTimeout(this.stallTimeout);
155
+ }
156
+ this.stallTimeout = setTimeout(() => {
157
+ this.args.onTimeout(`turn stalled after ${this.args.stallTimeoutMs}ms`);
158
+ }, this.args.stallTimeoutMs);
159
+ }
160
+ scheduleFlush() {
161
+ if (!this.args.livePersistence?.onFlush || this.flushTimer) {
162
+ return;
163
+ }
164
+ this.flushTimer = setTimeout(() => {
165
+ this.flushTimer = null;
166
+ void this.flushNow().catch(() => undefined);
167
+ }, this.args.livePersistence.flushWindowMs ?? 100);
168
+ }
169
+ trackOutput(activity) {
170
+ if (activity.type === "assistant_output.delta") {
171
+ this.finalOutput += activity.delta;
172
+ return;
173
+ }
174
+ if (activity.type === "assistant_output.completed") {
175
+ this.finalOutput = activity.text;
176
+ }
177
+ }
178
+ }
179
+ export function createPendingHarnessTurn(args) {
180
+ const controller = new HarnessTurnController(args);
181
+ let resolveTurn;
182
+ let rejectTurn;
183
+ const result = new Promise((resolve, reject) => {
184
+ resolveTurn = resolve;
185
+ rejectTurn = reject;
186
+ });
187
+ return {
188
+ controller,
189
+ result,
190
+ resolve: resolveTurn,
191
+ reject: rejectTurn,
192
+ };
193
+ }
194
+ export async function terminateProcess(process, gracefulTimeoutMs, hardKillTimeoutMs) {
195
+ if (process.exitCode !== null || process.killed) {
196
+ return;
197
+ }
198
+ const closed = waitForProcessClose(process);
199
+ process.kill("SIGTERM");
200
+ if (await raceWithTimeout(closed, gracefulTimeoutMs)) {
201
+ return;
202
+ }
203
+ if (process.exitCode === null && !process.killed) {
204
+ process.kill("SIGKILL");
205
+ }
206
+ await raceWithTimeout(closed, hardKillTimeoutMs);
207
+ }
208
+ export function waitForProcessClose(process) {
209
+ return new Promise((resolve) => {
210
+ if (process.exitCode !== null) {
211
+ resolve();
212
+ return;
213
+ }
214
+ const onClose = () => {
215
+ process.off("close", onClose);
216
+ resolve();
217
+ };
218
+ process.on("close", onClose);
219
+ });
220
+ }
221
+ async function raceWithTimeout(promise, timeoutMs) {
222
+ let resolved = false;
223
+ let timer = null;
224
+ try {
225
+ await Promise.race([
226
+ promise.then(() => {
227
+ resolved = true;
228
+ }),
229
+ new Promise((resolve) => {
230
+ timer = setTimeout(resolve, timeoutMs);
231
+ }),
232
+ ]);
233
+ return resolved;
234
+ }
235
+ finally {
236
+ if (timer) {
237
+ clearTimeout(timer);
238
+ }
239
+ }
240
+ }
@@ -0,0 +1,22 @@
1
+ import type { JsonValue } from "./types.js";
2
+ export type CanonicalToolSubjectKind = "command" | "query" | "path" | "url" | "pattern";
3
+ export interface CanonicalToolCall {
4
+ toolName: string | null;
5
+ attributes: Record<string, JsonValue> | undefined;
6
+ }
7
+ export interface CanonicalToolCallArgs {
8
+ canonicalToolName?: string | null;
9
+ rawToolName?: string | null;
10
+ operation?: string | null;
11
+ command?: string | null;
12
+ query?: string | null;
13
+ path?: string | null;
14
+ url?: string | null;
15
+ pattern?: string | null;
16
+ cwd?: string | null;
17
+ resultPreview?: string | null;
18
+ input?: JsonValue;
19
+ attributes?: Record<string, JsonValue>;
20
+ }
21
+ export declare function buildCanonicalToolCall(args: CanonicalToolCallArgs): CanonicalToolCall;
22
+ //# sourceMappingURL=tool-semantics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-semantics.d.ts","sourceRoot":"","sources":["../src/tool-semantics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,MAAM,wBAAwB,GAChC,SAAS,GACT,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC;CACnD;AAED,MAAM,WAAW,qBAAqB;IACpC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACxC;AAyDD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,qBAAqB,GAC1B,iBAAiB,CAqHnB"}
@@ -0,0 +1,241 @@
1
+ const TOOL_NAME_ALIASES = {
2
+ bash: { toolName: "shell", operation: "exec" },
3
+ shell: { toolName: "shell", operation: "exec" },
4
+ commandexecution: { toolName: "shell", operation: "exec" },
5
+ read: { toolName: "file", operation: "read" },
6
+ write: { toolName: "file", operation: "write" },
7
+ edit: { toolName: "file", operation: "edit" },
8
+ multiedit: { toolName: "file", operation: "edit" },
9
+ glob: { toolName: "file", operation: "glob" },
10
+ grep: { toolName: "file", operation: "grep" },
11
+ ls: { toolName: "file", operation: "list" },
12
+ list: { toolName: "file", operation: "list" },
13
+ image: { toolName: "image", operation: "view" },
14
+ imageview: { toolName: "image", operation: "view" },
15
+ viewimage: { toolName: "image", operation: "view" },
16
+ web: { toolName: "web", operation: null },
17
+ websearch: { toolName: "web", operation: "search" },
18
+ webfetch: { toolName: "web", operation: "fetch" },
19
+ openpage: { toolName: "web", operation: "open" },
20
+ findinpage: { toolName: "web", operation: "find" },
21
+ mcp: { toolName: "mcp", operation: null },
22
+ mcptoolcall: { toolName: "mcp", operation: null },
23
+ };
24
+ const TOOL_OPERATION_ALIASES = {
25
+ bash: "exec",
26
+ shell: "exec",
27
+ command: "exec",
28
+ commandexecution: "exec",
29
+ execute: "exec",
30
+ exec: "exec",
31
+ read: "read",
32
+ write: "write",
33
+ edit: "edit",
34
+ multiedit: "edit",
35
+ update: "edit",
36
+ ls: "list",
37
+ list: "list",
38
+ glob: "glob",
39
+ grep: "grep",
40
+ search: "search",
41
+ websearch: "search",
42
+ webfetch: "fetch",
43
+ fetch: "fetch",
44
+ openpage: "open",
45
+ open: "open",
46
+ findinpage: "find",
47
+ find: "find",
48
+ view: "view",
49
+ imageview: "view",
50
+ };
51
+ export function buildCanonicalToolCall(args) {
52
+ const rawToolName = cleanString(args.rawToolName);
53
+ const canonicalToolName = cleanString(args.canonicalToolName);
54
+ const operation = cleanString(args.operation);
55
+ const inputRecord = asRecord(args.input);
56
+ const inferredName = inferToolName(rawToolName);
57
+ const toolName = normalizeToolIdentifier(canonicalToolName) ??
58
+ inferredName.toolName ??
59
+ normalizeToolIdentifier(rawToolName);
60
+ const toolOperation = normalizeToolOperation(operation) ??
61
+ inferredName.operation ??
62
+ normalizeToolOperation(canonicalToolName) ??
63
+ null;
64
+ const command = cleanString(args.command) ??
65
+ readPreferredInputString(inputRecord, ["command", "cmd"]);
66
+ const query = cleanString(args.query) ??
67
+ readPreferredInputString(inputRecord, ["query", "search_query", "searchQuery"]) ??
68
+ readStringArrayValue(inputRecord?.queries).at(0) ??
69
+ null;
70
+ const url = cleanString(args.url) ??
71
+ readPreferredInputString(inputRecord, ["url", "page_url", "pageUrl"]);
72
+ const path = cleanString(args.path) ??
73
+ readPreferredInputString(inputRecord, [
74
+ "path",
75
+ "file_path",
76
+ "filePath",
77
+ "directory_path",
78
+ "directoryPath",
79
+ "target_path",
80
+ "targetPath",
81
+ ]) ??
82
+ readStringArrayValue(inputRecord?.paths).at(0) ??
83
+ null;
84
+ const pattern = cleanString(args.pattern) ??
85
+ readPreferredInputString(inputRecord, [
86
+ "pattern",
87
+ "glob",
88
+ "search_pattern",
89
+ "searchPattern",
90
+ ]);
91
+ const cwd = cleanString(args.cwd) ??
92
+ readPreferredInputString(inputRecord, ["cwd", "working_directory", "workingDirectory"]);
93
+ const resultPreview = cleanString(args.resultPreview);
94
+ const toolInputPreview = buildToolInputPreview(args.input);
95
+ const subject = command ?? query ?? url ?? path ?? pattern ?? null;
96
+ const subjectKind = command != null
97
+ ? "command"
98
+ : query != null
99
+ ? "query"
100
+ : url != null
101
+ ? "url"
102
+ : path != null
103
+ ? "path"
104
+ : pattern != null
105
+ ? "pattern"
106
+ : null;
107
+ const attributes = {
108
+ ...(args.attributes ?? {}),
109
+ };
110
+ if (rawToolName &&
111
+ rawToolName.length > 0 &&
112
+ normalizeToolIdentifier(rawToolName) !== toolName) {
113
+ attributes.tool_raw_name = rawToolName;
114
+ }
115
+ if (toolOperation) {
116
+ attributes.tool_operation = toolOperation;
117
+ }
118
+ if (subject && subjectKind) {
119
+ attributes.tool_subject = subject;
120
+ attributes.tool_subject_kind = subjectKind;
121
+ }
122
+ if (command) {
123
+ attributes.command = command;
124
+ }
125
+ if (query) {
126
+ attributes.query = query;
127
+ }
128
+ if (url) {
129
+ attributes.url = url;
130
+ }
131
+ if (path) {
132
+ attributes.path = path;
133
+ }
134
+ if (pattern) {
135
+ attributes.pattern = pattern;
136
+ }
137
+ if (cwd) {
138
+ attributes.cwd = cwd;
139
+ }
140
+ if (resultPreview) {
141
+ attributes.result_preview = resultPreview;
142
+ }
143
+ if (!subject && toolInputPreview) {
144
+ attributes.tool_input_preview = toolInputPreview;
145
+ }
146
+ return {
147
+ toolName,
148
+ attributes: Object.keys(attributes).length > 0 ? attributes : undefined,
149
+ };
150
+ }
151
+ function inferToolName(rawToolName) {
152
+ if (!rawToolName) {
153
+ return { toolName: null, operation: null };
154
+ }
155
+ const normalized = normalizeLookupKey(rawToolName);
156
+ const alias = TOOL_NAME_ALIASES[normalized];
157
+ if (alias) {
158
+ return {
159
+ toolName: alias.toolName,
160
+ operation: alias.operation ?? null,
161
+ };
162
+ }
163
+ return {
164
+ toolName: normalizeToolIdentifier(rawToolName),
165
+ operation: null,
166
+ };
167
+ }
168
+ function normalizeToolIdentifier(value) {
169
+ if (!value) {
170
+ return null;
171
+ }
172
+ const collapsed = value
173
+ .replace(/([a-z0-9])([A-Z])/gu, "$1_$2")
174
+ .replace(/[^A-Za-z0-9]+/gu, "_")
175
+ .replace(/^_+|_+$/gu, "")
176
+ .toLowerCase();
177
+ return collapsed.length > 0 ? collapsed : null;
178
+ }
179
+ function normalizeToolOperation(value) {
180
+ if (!value) {
181
+ return null;
182
+ }
183
+ const normalized = normalizeLookupKey(value);
184
+ return TOOL_OPERATION_ALIASES[normalized] ?? normalizeToolIdentifier(value);
185
+ }
186
+ function normalizeLookupKey(value) {
187
+ return value.replace(/[^A-Za-z0-9]+/gu, "").toLowerCase();
188
+ }
189
+ function readPreferredInputString(input, keys) {
190
+ if (!input) {
191
+ return null;
192
+ }
193
+ for (const key of keys) {
194
+ const value = cleanString(input[key]);
195
+ if (value) {
196
+ return value;
197
+ }
198
+ }
199
+ return null;
200
+ }
201
+ function readStringArrayValue(value) {
202
+ if (!Array.isArray(value)) {
203
+ return [];
204
+ }
205
+ return value.filter((entry) => typeof entry === "string");
206
+ }
207
+ function asRecord(value) {
208
+ if (!value || Array.isArray(value) || typeof value !== "object") {
209
+ return null;
210
+ }
211
+ return value;
212
+ }
213
+ function cleanString(value) {
214
+ return typeof value === "string" && value.trim().length > 0
215
+ ? value.trim()
216
+ : null;
217
+ }
218
+ function buildToolInputPreview(value) {
219
+ if (value == null) {
220
+ return null;
221
+ }
222
+ const normalized = typeof value === "string" ? value.trim() || null : safeJsonStringify(value);
223
+ if (!normalized) {
224
+ return null;
225
+ }
226
+ return truncateText(normalized, 240);
227
+ }
228
+ function safeJsonStringify(value) {
229
+ try {
230
+ const serialized = JSON.stringify(value);
231
+ return serialized && serialized !== "{}" && serialized !== "[]"
232
+ ? serialized
233
+ : null;
234
+ }
235
+ catch {
236
+ return null;
237
+ }
238
+ }
239
+ function truncateText(value, limit) {
240
+ return value.length <= limit ? value : `${value.slice(0, limit - 1)}…`;
241
+ }