@ai-sdk/harness-codex 1.0.126 → 1.0.128

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.
@@ -1,156 +0,0 @@
1
- export type ToolRelayCall = {
2
- toolName: string;
3
- input: unknown;
4
- };
5
-
6
- export type ToolRelayResult = {
7
- output: unknown;
8
- isError?: boolean;
9
- };
10
-
11
- export class ToolRelayAuthorizer {
12
- private readonly ttlMs: number;
13
- private readonly now: () => number;
14
- private readonly authorizations: Array<{ key: string; expiresAt: number }> =
15
- [];
16
- private readonly pendingRequests: Array<{
17
- key: string;
18
- expiresAt: number;
19
- timeout: ReturnType<typeof setTimeout>;
20
- resolve: (authorized: boolean) => void;
21
- }> = [];
22
-
23
- constructor({
24
- ttlMs = 10_000,
25
- now = Date.now,
26
- }: {
27
- ttlMs?: number;
28
- now?: () => number;
29
- } = {}) {
30
- this.ttlMs = ttlMs;
31
- this.now = now;
32
- }
33
-
34
- authorizeToolCall(call: ToolRelayCall): void {
35
- this.pruneExpired();
36
- const key = toolRelayCallKey(call);
37
- const pendingRequestIndex = this.pendingRequests.findIndex(
38
- request => request.key === key,
39
- );
40
- if (pendingRequestIndex !== -1) {
41
- const [pendingRequest] = this.pendingRequests.splice(
42
- pendingRequestIndex,
43
- 1,
44
- );
45
- clearTimeout(pendingRequest.timeout);
46
- pendingRequest.resolve(true);
47
- return;
48
- }
49
- this.authorizations.push({
50
- key,
51
- expiresAt: this.now() + this.ttlMs,
52
- });
53
- }
54
-
55
- waitForToolCallAuthorization(call: ToolRelayCall): Promise<boolean> {
56
- this.pruneExpired();
57
- const key = toolRelayCallKey(call);
58
- const authorizationIndex = this.authorizations.findIndex(
59
- authorization => authorization.key === key,
60
- );
61
- if (authorizationIndex !== -1) {
62
- this.authorizations.splice(authorizationIndex, 1);
63
- return Promise.resolve(true);
64
- }
65
-
66
- const expiresAt = this.now() + this.ttlMs;
67
- return new Promise(resolve => {
68
- const pendingRequest = {
69
- key,
70
- expiresAt,
71
- timeout: setTimeout(() => {
72
- const index = this.pendingRequests.indexOf(pendingRequest);
73
- if (index !== -1) this.pendingRequests.splice(index, 1);
74
- resolve(false);
75
- }, this.ttlMs),
76
- resolve,
77
- };
78
- this.pendingRequests.push(pendingRequest);
79
- });
80
- }
81
-
82
- close(): void {
83
- this.authorizations.length = 0;
84
- for (const pendingRequest of this.pendingRequests.splice(0)) {
85
- clearTimeout(pendingRequest.timeout);
86
- pendingRequest.resolve(false);
87
- }
88
- }
89
-
90
- private pruneExpired(): void {
91
- const now = this.now();
92
- for (let i = this.authorizations.length - 1; i >= 0; i--) {
93
- if (this.authorizations[i].expiresAt <= now) {
94
- this.authorizations.splice(i, 1);
95
- }
96
- }
97
- for (let i = this.pendingRequests.length - 1; i >= 0; i--) {
98
- const pendingRequest = this.pendingRequests[i];
99
- if (pendingRequest.expiresAt <= now) {
100
- this.pendingRequests.splice(i, 1);
101
- clearTimeout(pendingRequest.timeout);
102
- pendingRequest.resolve(false);
103
- }
104
- }
105
- }
106
- }
107
-
108
- export class ToolRelayPendingCalls {
109
- private readonly calls = new Map<string, Promise<ToolRelayResult>>();
110
-
111
- begin({
112
- call,
113
- run,
114
- }: {
115
- call: ToolRelayCall;
116
- run: () => Promise<ToolRelayResult>;
117
- }): { result: Promise<ToolRelayResult>; isNew: boolean } {
118
- const key = toolRelayCallKey(call);
119
- const existing = this.calls.get(key);
120
- if (existing) return { result: existing, isNew: false };
121
-
122
- const result = run();
123
- this.calls.set(key, result);
124
- void result
125
- .finally(() => {
126
- if (this.calls.get(key) === result) {
127
- this.calls.delete(key);
128
- }
129
- })
130
- .catch(() => {});
131
- return { result, isNew: true };
132
- }
133
- }
134
-
135
- function toolRelayCallKey({ toolName, input }: ToolRelayCall): string {
136
- return `${toolName}\0${canonicalJson(input ?? {})}`;
137
- }
138
-
139
- function canonicalJson(value: unknown): string {
140
- return JSON.stringify(normalizeJsonValue(value));
141
- }
142
-
143
- function normalizeJsonValue(value: unknown): unknown {
144
- if (Array.isArray(value)) {
145
- return value.map(normalizeJsonValue);
146
- }
147
- if (value && typeof value === 'object') {
148
- return Object.fromEntries(
149
- Object.entries(value as Record<string, unknown>)
150
- .filter(([, entryValue]) => entryValue !== undefined)
151
- .sort(([left], [right]) => left.localeCompare(right))
152
- .map(([key, entryValue]) => [key, normalizeJsonValue(entryValue)]),
153
- );
154
- }
155
- return value;
156
- }
@@ -1,119 +0,0 @@
1
- import { createServer, type Server } from 'node:http';
2
- import {
3
- ToolRelayAuthorizer,
4
- ToolRelayPendingCalls,
5
- type ToolRelayCall,
6
- } from './tool-relay-auth';
7
-
8
- export type ToolRelay = {
9
- port: number;
10
- close(): void;
11
- authorizeToolCall(call: ToolRelayCall): void;
12
- };
13
-
14
- export async function startAuthorizedToolRelay({
15
- tools,
16
- emit,
17
- requestToolResult,
18
- authorizer = new ToolRelayAuthorizer(),
19
- }: {
20
- tools: ReadonlyArray<{ name: string }>;
21
- emit: (message: Record<string, unknown>) => void;
22
- requestToolResult: (
23
- toolCallId: string,
24
- ) => Promise<{ output: unknown; isError?: boolean }>;
25
- authorizer?: ToolRelayAuthorizer;
26
- }): Promise<ToolRelay> {
27
- const toolNames = new Set(tools.map(tool => tool.name));
28
- const pendingCalls = new ToolRelayPendingCalls();
29
-
30
- const server = createServer(async (req, res) => {
31
- try {
32
- if (req.method !== 'POST' || req.url !== '/') {
33
- res.writeHead(401, { 'Content-Type': 'application/json' });
34
- res.end(JSON.stringify({ error: 'unauthorized tool relay request' }));
35
- return;
36
- }
37
- const chunks: Buffer[] = [];
38
- for await (const chunk of req) {
39
- chunks.push(chunk as Buffer);
40
- }
41
- const body = Buffer.concat(chunks).toString('utf8');
42
- const { requestId, toolName, input } = JSON.parse(body) as {
43
- requestId: string;
44
- toolName: string;
45
- input: unknown;
46
- };
47
-
48
- if (!toolNames.has(toolName)) {
49
- res.writeHead(403, { 'Content-Type': 'application/json' });
50
- res.end(
51
- JSON.stringify({ error: `Tool "${toolName}" is not available` }),
52
- );
53
- return;
54
- }
55
- const relayCall = { toolName, input };
56
- if (!(await authorizer.waitForToolCallAuthorization(relayCall))) {
57
- res.writeHead(401, { 'Content-Type': 'application/json' });
58
- res.end(JSON.stringify({ error: 'unauthorized tool relay request' }));
59
- return;
60
- }
61
-
62
- const { result } = pendingCalls.begin({
63
- call: relayCall,
64
- run: async () => {
65
- emit({
66
- type: 'tool-call',
67
- toolCallId: requestId,
68
- toolName,
69
- input: JSON.stringify(input ?? {}),
70
- providerExecuted: false,
71
- });
72
-
73
- const toolResult = await requestToolResult(requestId);
74
- emit({
75
- type: 'tool-result',
76
- toolCallId: requestId,
77
- toolName,
78
- result: toolResult.output ?? null,
79
- isError: !!toolResult.isError,
80
- });
81
- return toolResult;
82
- },
83
- });
84
- const { output } = await result;
85
-
86
- res.writeHead(200, { 'Content-Type': 'application/json' });
87
- res.end(JSON.stringify({ result: output }));
88
- } catch (error) {
89
- res.writeHead(500, { 'Content-Type': 'application/json' });
90
- res.end(
91
- JSON.stringify({
92
- error: error instanceof Error ? error.message : String(error),
93
- }),
94
- );
95
- }
96
- });
97
-
98
- await new Promise<void>(resolve =>
99
- server.listen(0, '127.0.0.1', () => resolve()),
100
- );
101
- const address = server.address();
102
- if (!address || typeof address === 'string') {
103
- throw new Error('tool relay did not expose a numeric port');
104
- }
105
- return {
106
- port: address.port,
107
- close: () => {
108
- authorizer.close();
109
- closeServer(server);
110
- },
111
- authorizeToolCall: call => authorizer.authorizeToolCall(call),
112
- };
113
- }
114
-
115
- function closeServer(server: Server): void {
116
- try {
117
- server.close();
118
- } catch {}
119
- }