@jrkropp/codex-js 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +94 -45
- package/dist/internal/codex/app-server/src/{bespoke_event_handling.d.ts → app_server_event_mapping.d.ts} +1 -1
- package/dist/internal/codex/app-server/src/message_processor.d.ts +11 -0
- package/dist/internal/codex/codex-api/src/endpoint/responses_websocket.d.ts +1 -1
- package/dist/runtime/index.d.ts +3 -3
- package/dist/server/app-server.d.ts +60 -0
- package/dist/server/dynamic-tools.d.ts +40 -0
- package/dist/server/index.d.ts +6 -1
- package/dist/server/index.js +501 -28
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @jrkropp/codex-js
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add high-level app-server helpers, dynamic tool definition helpers, connection
|
|
8
|
+
snapshot support, and pending server-request persistence contracts.
|
|
9
|
+
- Align public server terminology around app-server, connection, thread, turn,
|
|
10
|
+
dynamic tool, server request, server notification, and transport concepts.
|
|
11
|
+
- Replace the placeholder Cloudflare example with a deployable Worker + Durable
|
|
12
|
+
Object + Vite React example.
|
|
13
|
+
|
|
3
14
|
## 0.2.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,99 +1,148 @@
|
|
|
1
1
|
# @jrkropp/codex-js
|
|
2
2
|
|
|
3
|
-
Core TypeScript
|
|
3
|
+
Core TypeScript SDK for building Codex-backed applications. It includes the browser app-server client, platform-neutral server helpers, Codex-aligned runtime contracts, stores, model transport, and test utilities.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
|
|
8
|
+
npm install @jrkropp/codex-js
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Requirements:
|
|
12
12
|
|
|
13
13
|
- Node.js 20 or newer.
|
|
14
|
-
- ESM
|
|
15
|
-
- React is not a dependency
|
|
14
|
+
- ESM only. CommonJS output is not shipped.
|
|
15
|
+
- React is not a dependency. Install `@jrkropp/codex-js-react` only when you need packaged UI components.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Public Imports
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
import { createCodexAppServerClient } from "@jrkropp/codex-js/client";
|
|
21
|
-
import {
|
|
21
|
+
import { createCodexAppServer } from "@jrkropp/codex-js/server";
|
|
22
22
|
import { InMemoryThreadStore } from "@jrkropp/codex-js/testing";
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
The
|
|
25
|
+
The core package exposes only:
|
|
26
26
|
|
|
27
27
|
- `@jrkropp/codex-js`
|
|
28
28
|
- `@jrkropp/codex-js/client`
|
|
29
29
|
- `@jrkropp/codex-js/server`
|
|
30
30
|
- `@jrkropp/codex-js/testing`
|
|
31
31
|
|
|
32
|
-
There are no public
|
|
32
|
+
There are no public mirror or unstable imports.
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Server Quick Start
|
|
35
35
|
|
|
36
36
|
```ts
|
|
37
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
createCodexAppServer,
|
|
39
|
+
createModelClient,
|
|
40
|
+
defineDynamicTool,
|
|
41
|
+
dynamicToolResponse,
|
|
42
|
+
} from "@jrkropp/codex-js/server";
|
|
43
|
+
import { InMemoryThreadStore } from "@jrkropp/codex-js/testing";
|
|
38
44
|
|
|
39
|
-
const
|
|
40
|
-
|
|
45
|
+
const lookupStatus = defineDynamicTool({
|
|
46
|
+
name: "lookup_status",
|
|
47
|
+
description: "Look up the current deployment status.",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: { name: { type: "string" } },
|
|
51
|
+
required: ["name"],
|
|
52
|
+
additionalProperties: false,
|
|
53
|
+
},
|
|
54
|
+
async execute(args) {
|
|
55
|
+
return dynamicToolResponse.text(`${args.name} is healthy.`);
|
|
56
|
+
},
|
|
41
57
|
});
|
|
42
58
|
|
|
43
|
-
|
|
44
|
-
|
|
59
|
+
const appServer = createCodexAppServer({
|
|
60
|
+
threadStore: new InMemoryThreadStore(),
|
|
61
|
+
dynamicTools: [lookupStatus],
|
|
62
|
+
defaults: {
|
|
63
|
+
cwd: "/workspace",
|
|
64
|
+
model: "gpt-5-mini",
|
|
65
|
+
modelProvider: "openai",
|
|
66
|
+
},
|
|
67
|
+
createModelClient({ session, threadId }) {
|
|
68
|
+
return createModelClient({
|
|
69
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
70
|
+
installationId: "my-app",
|
|
71
|
+
sessionId: session.id,
|
|
72
|
+
threadId,
|
|
73
|
+
});
|
|
74
|
+
},
|
|
45
75
|
});
|
|
46
76
|
```
|
|
47
77
|
|
|
48
|
-
|
|
78
|
+
Create one app-server connection per WebSocket:
|
|
49
79
|
|
|
50
80
|
```ts
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
81
|
+
const connection = appServer.createConnection({
|
|
82
|
+
send(message) {
|
|
83
|
+
webSocket.send(message);
|
|
84
|
+
},
|
|
85
|
+
});
|
|
56
86
|
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
webSocket.addEventListener("message", (event) => {
|
|
88
|
+
void connection.accept(event.data);
|
|
59
89
|
});
|
|
60
90
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
send: (message) => {
|
|
64
|
-
// Write the serialized app-server event to your WebSocket.
|
|
65
|
-
console.log(message);
|
|
66
|
-
},
|
|
91
|
+
webSocket.addEventListener("close", () => {
|
|
92
|
+
void connection.close();
|
|
67
93
|
});
|
|
68
94
|
```
|
|
69
95
|
|
|
70
|
-
|
|
96
|
+
`createCodexAppServerRuntime` is still exported for advanced hosts that need to own message processing directly, but most applications should start with `createCodexAppServer`.
|
|
71
97
|
|
|
72
|
-
##
|
|
98
|
+
## Dynamic Tools
|
|
73
99
|
|
|
74
|
-
|
|
100
|
+
Use `defineDynamicTool` for server-executed tools. Use a namespace when a tool is deferred and loaded through Codex tool search.
|
|
75
101
|
|
|
76
|
-
```
|
|
77
|
-
|
|
102
|
+
```ts
|
|
103
|
+
const lookupInvoice = defineDynamicTool({
|
|
104
|
+
namespace: "billing",
|
|
105
|
+
name: "lookup_invoice",
|
|
106
|
+
description: "Look up an invoice by id.",
|
|
107
|
+
deferLoading: true,
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: { invoiceId: { type: "string" } },
|
|
111
|
+
required: ["invoiceId"],
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
},
|
|
114
|
+
async execute(args) {
|
|
115
|
+
return dynamicToolResponse.text(`Invoice ${args.invoiceId} is paid.`);
|
|
116
|
+
},
|
|
117
|
+
});
|
|
78
118
|
```
|
|
79
119
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
120
|
+
Tools with `execute` are resolved by the server. Tools without `execute` are surfaced as app-server requests so the client can resolve them.
|
|
121
|
+
|
|
122
|
+
## Browser Client
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { createCodexAppServerClient } from "@jrkropp/codex-js/client";
|
|
126
|
+
|
|
127
|
+
const appServer = createCodexAppServerClient({
|
|
128
|
+
url: async () => {
|
|
129
|
+
const session = await fetch("/api/codex/session", { method: "POST" });
|
|
130
|
+
const { webSocketUrl } = await session.json();
|
|
131
|
+
return webSocketUrl;
|
|
132
|
+
},
|
|
133
|
+
});
|
|
83
134
|
```
|
|
84
135
|
|
|
85
|
-
|
|
136
|
+
The browser never needs an OpenAI API key. Host applications should issue a short-lived app-server WebSocket URL from their backend.
|
|
137
|
+
|
|
138
|
+
## Cloudflare
|
|
86
139
|
|
|
87
|
-
|
|
140
|
+
The repository includes a deployable Cloudflare Worker + Durable Object + Vite React example:
|
|
88
141
|
|
|
89
142
|
```sh
|
|
90
|
-
pnpm dev:
|
|
91
|
-
pnpm dev:vite-react
|
|
143
|
+
pnpm dev:node-local
|
|
92
144
|
pnpm dev:cloudflare-example
|
|
145
|
+
pnpm --filter @jrkropp/codex-js-cloudflare-example deploy:dry-run
|
|
93
146
|
```
|
|
94
147
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
## Architecture
|
|
98
|
-
|
|
99
|
-
`@jrkropp/codex-js` is the non-React package. It owns the transport protocol, app-server client, server runtime helpers, stores, serializers, and testing primitives. UI components, shadcn exports, Tailwind output, and React-only dependencies live in `@jrkropp/codex-js-react`.
|
|
148
|
+
Use `examples/node-local` for the smallest local Node/Vite integration. Use `examples/cloudflare` for a deployable Worker + Durable Object integration with one-time WebSocket tickets, Durable Object SQLite storage, hibernating WebSockets, server-executed dynamic tools, and a deferred namespaced tool.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EventMsg } from "../../core/src/protocol.js";
|
|
2
2
|
import { serverRequestResolvedNotification, type AppServerProtocolEvent, type EventMappingContext, type ServerRequestCoreTarget } from "../../app-server-protocol/src/protocol/event-mapping.js";
|
|
3
3
|
export type { AppServerProtocolEvent, EventMappingContext, ServerRequestCoreTarget, };
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function mapCoreEventToAppServerEvents(msg: EventMsg, context: EventMappingContext): AppServerProtocolEvent[];
|
|
5
5
|
export { serverRequestResolvedNotification };
|
|
@@ -36,6 +36,15 @@ export type InitializedConnectionSessionState = {
|
|
|
36
36
|
experimentalApiEnabled: boolean;
|
|
37
37
|
optedOutNotificationMethods: ReadonlySet<string>;
|
|
38
38
|
};
|
|
39
|
+
export type CodexAppServerConnectionSnapshot = {
|
|
40
|
+
initialized: InitializedConnectionSessionSnapshot | null;
|
|
41
|
+
};
|
|
42
|
+
export type InitializedConnectionSessionSnapshot = {
|
|
43
|
+
appServerClientName: string;
|
|
44
|
+
clientVersion: string;
|
|
45
|
+
experimentalApiEnabled: boolean;
|
|
46
|
+
optedOutNotificationMethods: string[];
|
|
47
|
+
};
|
|
39
48
|
export declare class CodexAppServerConnectionSessionState {
|
|
40
49
|
readonly rpcGate: ConnectionRpcGate;
|
|
41
50
|
private initializedState;
|
|
@@ -46,6 +55,8 @@ export declare class CodexAppServerConnectionSessionState {
|
|
|
46
55
|
optedOutNotificationMethods(): ReadonlySet<string>;
|
|
47
56
|
appServerClientName(): string | null;
|
|
48
57
|
clientVersion(): string | null;
|
|
58
|
+
snapshot(): CodexAppServerConnectionSnapshot;
|
|
59
|
+
static fromSnapshot(snapshot?: CodexAppServerConnectionSnapshot | null): CodexAppServerConnectionSessionState;
|
|
49
60
|
}
|
|
50
61
|
export type CodexAppServerMessageProcessorOptions<Context = unknown> = {
|
|
51
62
|
connectionId?: ConnectionId;
|
|
@@ -3,7 +3,7 @@ import type { ResponseStream, ResponsesWsRequest, TurnState } from "../common.js
|
|
|
3
3
|
type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
4
4
|
type WorkerWebSocket = WebSocket & {
|
|
5
5
|
accept?: (options?: unknown) => void;
|
|
6
|
-
binaryType?:
|
|
6
|
+
binaryType?: "arraybuffer" | "blob";
|
|
7
7
|
};
|
|
8
8
|
export type ResponsesWebsocketClientInput = {
|
|
9
9
|
api_key: string;
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -15,12 +15,12 @@ export { CodexAppServerClientTransportError, createCodexAppServerClient, parseCo
|
|
|
15
15
|
export { jsonRpcInternalError, jsonRpcInvalidRequestError, jsonRpcParseError, parseClientTransportPayload, parseJsonRpcMessage, parseJsonRpcTransportPayload, parseServerTransportPayload, queuedOutgoingMessage, serializeJsonRpcError, serializeJsonRpcResponse, serializeOutgoingMessage, type ConnectionOrigin, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ParsedClientTransportMessage, type ParsedServerTransportMessage, type ParsedTransportPayload, type TransportEvent, } from "../internal/codex/app-server-transport/src/transport/mod.js";
|
|
16
16
|
export { OutgoingMessageSender, ThreadScopedOutgoingMessageSender, outgoingMessageToAppServerEvent, type ConnectionId, type ConnectionRequestId, type OutgoingError, type OutgoingMessage, type OutgoingResponse, type QueuedOutgoingMessage, type RequestContext, } from "../internal/codex/app-server/src/outgoing_message.js";
|
|
17
17
|
export { CodexAppServerRequestError } from "../internal/codex/app-server/src/request_processors/request_errors.js";
|
|
18
|
-
export { codexAppServerDeferredResponse, CodexAppServerConnectionSessionState, CodexAppServerMessageProcessor, type CodexAppServerMethodHandlers, type CodexAppServerRequestContext, type CodexAppServerDeferredResponse, type CodexAppServerConnectionRequestOutcome, type CodexAppServerMessageProcessorOptions, type InitializedConnectionSessionState, } from "../internal/codex/app-server/src/message_processor.js";
|
|
18
|
+
export { codexAppServerDeferredResponse, CodexAppServerConnectionSessionState, CodexAppServerMessageProcessor, type CodexAppServerMethodHandlers, type CodexAppServerRequestContext, type CodexAppServerDeferredResponse, type CodexAppServerConnectionSnapshot, type CodexAppServerConnectionRequestOutcome, type CodexAppServerMessageProcessorOptions, type InitializedConnectionSessionSnapshot, type InitializedConnectionSessionState, } from "../internal/codex/app-server/src/message_processor.js";
|
|
19
19
|
export { ConnectionRpcGate, ConnectionRpcGateClosedError, } from "../internal/codex/app-server/src/connection_rpc_gate.js";
|
|
20
20
|
export { RequestSerializationQueues, requestSerializationQueueKeyFromScope, type RequestSerializationQueueKey, } from "../internal/codex/app-server/src/request_serialization.js";
|
|
21
21
|
export { McpRequestProcessor, ThreadRequestProcessor, TurnRequestProcessor, type RuntimeSession, } from "../internal/codex/app-server/src/request_processors.js";
|
|
22
22
|
export { createCodexAppServerRuntime, type CodexAppServerEventSink, type CodexAppServerOutgoingSink, type CodexAppServerRuntime, type CodexAppServerRuntimeContext, type CodexAppServerRuntimeOptions, } from "../internal/codex/app-server/src/runtime.js";
|
|
23
|
-
export { AppServerSession, type CodexAppServer } from "../internal/codex/app-server-client/src/session.js";
|
|
23
|
+
export { AppServerSession, type CodexAppServer, } from "../internal/codex/app-server-client/src/session.js";
|
|
24
24
|
export { serverNotificationThreadTarget, serverRequestThreadId, threadEventSnapshotHasStarted, ThreadEventStore, type ServerNotificationThreadTarget, type ThreadBufferedEvent, type ThreadEventSnapshot, type ThreadTokenUsageSnapshot, } from "../internal/codex/app-server-client/src/thread_event_store.js";
|
|
25
25
|
export { PendingAppServerRequests, type AppServerRequestResolution, type ResolvedAppServerRequest, type UnsupportedAppServerRequest, } from "../internal/codex/app-server-client/src/pending_requests.js";
|
|
26
26
|
export { deniedRequestPermissionsResponse } from "../internal/codex/core/src/request_permissions.js";
|
|
@@ -36,7 +36,7 @@ export { ThreadHistoryBuilder } from "../internal/codex/core/src/thread-history-
|
|
|
36
36
|
export type { Turn as ThreadHistoryTurn, TurnStatus as ThreadHistoryTurnStatus, } from "../internal/codex/core/src/thread-history-builder.js";
|
|
37
37
|
export type { TextElement as CoreTextElement, UserInput as CoreUserInputItem, } from "../internal/codex/core/src/protocol/user_input.js";
|
|
38
38
|
export type { TurnItem as CoreTurnItem, UserMessageTurnItem as CoreUserMessageTurnItem, } from "../internal/codex/core/src/items.js";
|
|
39
|
-
export type { Model, ModelPreset } from "../internal/codex/core/src/model-provider.js";
|
|
39
|
+
export type { Model, ModelPreset, } from "../internal/codex/core/src/model-provider.js";
|
|
40
40
|
export { createModelClient, defaultModelsManager, ModelClientSession, ResponsesClient, ResponsesWebsocketClient, ResponsesWebsocketConnection, resolveReasoningEffortForModel, } from "../internal/codex/core/src/index.js";
|
|
41
41
|
export type { CreateModelClientInput, ModelClient, ModelClientSessionHandle, Prompt, ResponseEvent, ResponseStream, ResponsesApiRequest, ResponsesClientInput, ResponseCreateWsRequest, ResponseProcessedWsRequest, ResponsesWsRequest, } from "../internal/codex/core/src/index.js";
|
|
42
42
|
export { ThreadMemoryMode } from "../internal/codex/core/src/memory.js";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type CodexAppServerRuntime, type CodexAppServerRuntimeContext, type CodexAppServerRuntimeOptions, type CodexAppServerConnectionSnapshot, type ConnectionId, type JSONRPCErrorError, type RequestId, type ServerRequest, type ThreadStore } from "../runtime/index.js";
|
|
2
|
+
import { type DefinedDynamicTool } from "./dynamic-tools.js";
|
|
3
|
+
export type PendingServerRequestRecord = {
|
|
4
|
+
createdAt: number;
|
|
5
|
+
request: ServerRequest;
|
|
6
|
+
requestId: RequestId;
|
|
7
|
+
threadId: string;
|
|
8
|
+
};
|
|
9
|
+
export type PendingServerRequestStore = {
|
|
10
|
+
delete(requestId: RequestId): Promise<void> | void;
|
|
11
|
+
get(requestId: RequestId): Promise<PendingServerRequestRecord | null> | PendingServerRequestRecord | null;
|
|
12
|
+
list(): Promise<PendingServerRequestRecord[]> | PendingServerRequestRecord[];
|
|
13
|
+
put(record: PendingServerRequestRecord): Promise<void> | void;
|
|
14
|
+
take(requestId: RequestId): Promise<PendingServerRequestRecord | null> | PendingServerRequestRecord | null;
|
|
15
|
+
};
|
|
16
|
+
export type CodexAppServerDefaults = {
|
|
17
|
+
baseInstructions?: string;
|
|
18
|
+
cwd?: string;
|
|
19
|
+
model?: string;
|
|
20
|
+
modelProvider?: string;
|
|
21
|
+
source?: string;
|
|
22
|
+
threadSource?: string | null;
|
|
23
|
+
};
|
|
24
|
+
export type CreateCodexAppServerOptions<Context = CodexAppServerRuntimeContext> = Omit<CodexAppServerRuntimeOptions<Context>, "sendOutgoingTransportMessage" | "store"> & {
|
|
25
|
+
defaults?: CodexAppServerDefaults;
|
|
26
|
+
dynamicTools?: readonly DefinedDynamicTool<Context>[];
|
|
27
|
+
pendingServerRequests?: PendingServerRequestStore;
|
|
28
|
+
/** @deprecated Use threadStore. */
|
|
29
|
+
store?: ThreadStore;
|
|
30
|
+
threadStore?: ThreadStore;
|
|
31
|
+
};
|
|
32
|
+
export type CodexAppServerConnection<Context = CodexAppServerRuntimeContext> = {
|
|
33
|
+
accept(message: unknown): Promise<void>;
|
|
34
|
+
close(): Promise<void>;
|
|
35
|
+
connectionId: ConnectionId;
|
|
36
|
+
processor: ReturnType<CodexAppServerRuntime<Context>["createMessageProcessor"]>;
|
|
37
|
+
snapshot(): CodexAppServerConnectionSnapshot;
|
|
38
|
+
};
|
|
39
|
+
export type CreateCodexAppServerConnectionOptions<Context = CodexAppServerRuntimeContext> = {
|
|
40
|
+
connectionId?: ConnectionId;
|
|
41
|
+
context?: Context;
|
|
42
|
+
onSnapshot?: (snapshot: CodexAppServerConnectionSnapshot) => void | Promise<void>;
|
|
43
|
+
send(message: string): void | Promise<void>;
|
|
44
|
+
snapshot?: CodexAppServerConnectionSnapshot | null;
|
|
45
|
+
};
|
|
46
|
+
export type CreatedCodexAppServer<Context = CodexAppServerRuntimeContext> = CodexAppServerRuntime<Context> & {
|
|
47
|
+
createConnection(options: CreateCodexAppServerConnectionOptions<Context>): CodexAppServerConnection<Context>;
|
|
48
|
+
pendingServerRequests: PendingServerRequestStore;
|
|
49
|
+
};
|
|
50
|
+
export declare class InMemoryPendingServerRequestStore implements PendingServerRequestStore {
|
|
51
|
+
private readonly records;
|
|
52
|
+
delete(requestId: RequestId): void;
|
|
53
|
+
get(requestId: RequestId): PendingServerRequestRecord | null;
|
|
54
|
+
list(): PendingServerRequestRecord[];
|
|
55
|
+
put(record: PendingServerRequestRecord): void;
|
|
56
|
+
take(requestId: RequestId): PendingServerRequestRecord | null;
|
|
57
|
+
}
|
|
58
|
+
export declare function createCodexAppServer<Context = CodexAppServerRuntimeContext>(options: CreateCodexAppServerOptions<Context>): CreatedCodexAppServer<Context>;
|
|
59
|
+
export declare function createCodexAppServerConnection<Context = CodexAppServerRuntimeContext>(appServer: CreatedCodexAppServer<Context>, options: CreateCodexAppServerConnectionOptions<Context>): CodexAppServerConnection<Context>;
|
|
60
|
+
export declare function jsonRpcErrorFromUnknown(error: unknown): JSONRPCErrorError;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DynamicToolCallParams, DynamicToolCallResponse, DynamicToolSpec } from "../runtime/index.js";
|
|
2
|
+
export type DynamicToolExecutionContext<Context = unknown> = {
|
|
3
|
+
callId: string;
|
|
4
|
+
context?: Context;
|
|
5
|
+
namespace: string | null;
|
|
6
|
+
params: DynamicToolCallParams;
|
|
7
|
+
threadId: string;
|
|
8
|
+
tool: string;
|
|
9
|
+
turnId: string;
|
|
10
|
+
};
|
|
11
|
+
export type DynamicToolExecute<Context = unknown, Args = unknown> = (args: Args, context: DynamicToolExecutionContext<Context>) => DynamicToolCallResponse | Promise<DynamicToolCallResponse>;
|
|
12
|
+
export type DynamicToolDefinition<Context = unknown, Args = unknown> = {
|
|
13
|
+
deferLoading?: boolean;
|
|
14
|
+
description: string;
|
|
15
|
+
execute?: DynamicToolExecute<Context, Args>;
|
|
16
|
+
inputSchema: unknown;
|
|
17
|
+
name: string;
|
|
18
|
+
namespace?: string | null;
|
|
19
|
+
};
|
|
20
|
+
export type DefinedDynamicTool<Context = unknown, Args = unknown> = Readonly<DynamicToolDefinition<Context, Args>>;
|
|
21
|
+
export type DefinedDynamicToolset<Context = unknown> = readonly DefinedDynamicTool<Context>[];
|
|
22
|
+
type DynamicToolDefinitionForValidation = {
|
|
23
|
+
deferLoading?: boolean;
|
|
24
|
+
description: string;
|
|
25
|
+
inputSchema: unknown;
|
|
26
|
+
name: string;
|
|
27
|
+
namespace?: string | null;
|
|
28
|
+
};
|
|
29
|
+
export declare const dynamicToolResponse: {
|
|
30
|
+
text(text: string): DynamicToolCallResponse;
|
|
31
|
+
image(imageUrl: string): DynamicToolCallResponse;
|
|
32
|
+
error(message: string): DynamicToolCallResponse;
|
|
33
|
+
};
|
|
34
|
+
export declare function defineDynamicTool<Context = unknown, Args = unknown>(definition: DynamicToolDefinition<Context, Args>): DefinedDynamicTool<Context, Args>;
|
|
35
|
+
export declare function defineDynamicToolset<Context = unknown>(definitions: readonly DynamicToolDefinition<Context>[]): DefinedDynamicToolset<Context>;
|
|
36
|
+
export declare function dynamicToolSpecFromDefinition(tool: DynamicToolDefinitionForValidation): DynamicToolSpec;
|
|
37
|
+
export declare function dynamicToolSpecsFromDefinitions(tools: readonly DefinedDynamicTool[]): DynamicToolSpec[];
|
|
38
|
+
export declare function findDynamicTool<Context>(tools: readonly DefinedDynamicTool<Context>[], params: DynamicToolCallParams): DefinedDynamicTool<Context> | null;
|
|
39
|
+
export declare function validateDynamicToolDefinitions(tools: readonly DynamicToolDefinitionForValidation[]): void;
|
|
40
|
+
export {};
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
export { AppServerSession, asThreadId, BaseInstructions, CodexAppServerClientTransportError, CodexAppServerConnectionSessionState, codexAppServerDeferredResponse, CodexAppServerMessageProcessor, CodexAppServerRequestError, CodexMcpConnectionManagerAdapter, ConnectionRpcGate, ConnectionRpcGateClosedError, createCodexAppServerClient, createCodexAppServerRuntime, createModelClient, deniedRequestPermissionsResponse, EmptyMcpConnectionManager, InMemoryThreadStore, jsonRpcInternalError, jsonRpcInvalidRequestError, jsonRpcParseError, LiveThread, LocalThreadStore, McpRequestProcessor, ModelClientSession, OutgoingMessageSender, outgoingMessageToAppServerEvent, parseClientTransportPayload, parseCodexAppServerEvent, parseJsonRpcMessage, parseJsonRpcTransportPayload, parseServerTransportPayload, PendingAppServerRequests, queuedOutgoingMessage, requestMethodName, RequestSerializationQueues, requestSerializationQueueKeyFromScope, requestTyped, ResponsesClient, ResponsesWebsocketClient, ResponsesWebsocketConnection, serializeJsonRpcError, serializeJsonRpcResponse, serializeOutgoingMessage, serverNotificationRequiresDelivery, serverNotificationThreadTarget, serverRequestThreadId, setRenderedThreadConnectionStatus, SortDirection, StaticMcpConnectionManager, ThreadEventPersistenceMode, threadEventSnapshotHasStarted, ThreadEventStore, ThreadHistoryBuilder, ThreadMemoryMode, ThreadRequestProcessor, ThreadScopedOutgoingMessageSender, ThreadSortKey, TurnRequestProcessor, } from "../runtime/index.js";
|
|
2
|
-
export
|
|
2
|
+
export { createCodexAppServer, createCodexAppServerConnection, InMemoryPendingServerRequestStore, jsonRpcErrorFromUnknown, } from "./app-server.js";
|
|
3
|
+
export { dynamicToolResponse, defineDynamicTool, defineDynamicToolset, dynamicToolSpecFromDefinition, dynamicToolSpecsFromDefinitions, findDynamicTool, validateDynamicToolDefinitions, } from "./dynamic-tools.js";
|
|
4
|
+
export { dynamicToolResponse as codexDynamicToolResponse, defineDynamicTool as defineCodexDynamicTool, defineDynamicToolset as defineCodexDynamicToolset, } from "./dynamic-tools.js";
|
|
5
|
+
export type { AppendThreadItemsParams, AppServerEvent, AppServerRequestHandle, ArchiveThreadParams, ClientRequest, ClientRequestSerializationScope, CodexAppServer, CodexAppServerClientConnectionStatus, CodexAppServerClientOptions, CodexAppServerDeferredResponse, CodexAppServerEventSink, CodexAppServerMethodHandlers, CodexAppServerOutgoingSink, CodexAppServerRequestContext, CodexAppServerRuntime, CodexAppServerRuntimeContext, CodexAppServerRuntimeOptions, CodexAppServerConnectionSnapshot, CodexAppServerRuntimeOptions as CreateCodexAppServerRuntimeOptions, CodexAppServerRuntime as CreatedCodexAppServerRuntime, CollaborationMode, CollaborationModeListParams, CollaborationModeListResponse, CommandExecutionRequestApprovalResponse, ConnectionId, ConnectionOrigin, ConnectionRequestId, CreateModelClientInput, CreateThreadParams, DynamicToolCallParams, DynamicToolCallResponse, DynamicToolSpec, DynamicToolSpecWire, FileChangeRequestApprovalResponse, InitializedConnectionSessionState, InMemoryThreadStoreCalls, JSONRPCError, JSONRPCErrorError, JSONRPCMessage, JSONRPCNotification, JSONRPCRequest, JSONRPCResponse, ListMcpServerStatusParams, ListMcpServerStatusResponse, ListThreadsParams, LocalThreadStoreConfig, LoadThreadHistoryParams, McpConnectionManager, McpResourceInfo, McpResourceReadParams, McpResourceReadResponse, McpResourceTemplateInfo, McpRuntimeEnvironment, McpServerElicitationRequestResponse, McpServerOauthLoginParams, McpServerOauthLoginResponse, McpServerRefreshConfig, McpServerRefreshResponse, McpServerStatus, McpServerStatusListOptions, McpServerToolCallParams, McpServerToolCallResponse, McpToolInfo, Model, ModelClient, ModelClientSessionHandle, ModelPreset, OutgoingError, OutgoingMessage, OutgoingResponse, ParsedClientTransportMessage, ParsedServerTransportMessage, ParsedTransportPayload, PermissionsRequestApprovalResponse, Prompt, QueuedOutgoingMessage, RequestContext, RequestId, RequestSerializationQueueKey, ReadThreadByRolloutPathParams, ReadThreadParams, ResumeThreadParams, ResponseCreateWsRequest, ResponseEvent, ResponseProcessedWsRequest, ResponseStream, ResponsesApiRequest, ResponsesClientInput, ResponsesWsRequest, Result, RolloutItem, RuntimeSession, SandboxPolicy, ServerNotification, ServerNotificationThreadTarget, ServerRequest, StoredThread, StoredThreadHistory, Thread, ThreadArchiveParams, ThreadArchiveResponse, ThreadBufferedEvent, ThreadCompactStartParams, ThreadCompactStartResponse, ThreadEventSnapshot, ThreadId, ThreadItem, ThreadListParams, ThreadListResponse, ThreadMetadataPatch, ThreadMetadataUpdateParams, ThreadMetadataUpdateResponse, ThreadPage, ThreadPersistenceMetadata, UpdateThreadMetadataParams, ThreadReadParams, ThreadReadResponse, ThreadResumeParams, ThreadResumeResponse, ThreadSetNameParams, ThreadSetNameResponse, ThreadStartParams, ThreadStartResponse, ThreadStore, ThreadTokenUsageSnapshot, ThreadUnarchiveParams, ThreadUnarchiveResponse, ToolRequestUserInputResponse, TransportEvent, Turn, TurnInterruptParams, TurnInterruptResponse, TurnStartParams, TurnStartResponse, TurnSteerParams, TurnSteerResponse, TypedRequestError, UserInput, } from "../runtime/index.js";
|
|
6
|
+
export type { CodexAppServerConnection, CodexAppServerDefaults, CreateCodexAppServerConnectionOptions, CreateCodexAppServerOptions, CreatedCodexAppServer, PendingServerRequestRecord, PendingServerRequestStore, } from "./app-server.js";
|
|
7
|
+
export type { DefinedDynamicTool, DefinedDynamicToolset, DynamicToolDefinition, DynamicToolExecute, DynamicToolExecutionContext, } from "./dynamic-tools.js";
|
package/dist/server/index.js
CHANGED
|
@@ -4006,7 +4006,7 @@ function requestSerializationQueueKeyFromScope(connectionId, scope) {
|
|
|
4006
4006
|
}
|
|
4007
4007
|
|
|
4008
4008
|
// src/internal/codex/app-server/src/message_processor.ts
|
|
4009
|
-
var CodexAppServerConnectionSessionState = class {
|
|
4009
|
+
var CodexAppServerConnectionSessionState = class _CodexAppServerConnectionSessionState {
|
|
4010
4010
|
rpcGate = new ConnectionRpcGate();
|
|
4011
4011
|
initializedState = null;
|
|
4012
4012
|
constructor(initializedState) {
|
|
@@ -4033,6 +4033,31 @@ var CodexAppServerConnectionSessionState = class {
|
|
|
4033
4033
|
clientVersion() {
|
|
4034
4034
|
return this.initializedState?.clientVersion ?? null;
|
|
4035
4035
|
}
|
|
4036
|
+
snapshot() {
|
|
4037
|
+
return {
|
|
4038
|
+
initialized: this.initializedState ? {
|
|
4039
|
+
appServerClientName: this.initializedState.appServerClientName,
|
|
4040
|
+
clientVersion: this.initializedState.clientVersion,
|
|
4041
|
+
experimentalApiEnabled: this.initializedState.experimentalApiEnabled,
|
|
4042
|
+
optedOutNotificationMethods: Array.from(
|
|
4043
|
+
this.initializedState.optedOutNotificationMethods
|
|
4044
|
+
)
|
|
4045
|
+
} : null
|
|
4046
|
+
};
|
|
4047
|
+
}
|
|
4048
|
+
static fromSnapshot(snapshot) {
|
|
4049
|
+
if (!snapshot?.initialized) {
|
|
4050
|
+
return new _CodexAppServerConnectionSessionState();
|
|
4051
|
+
}
|
|
4052
|
+
return new _CodexAppServerConnectionSessionState({
|
|
4053
|
+
appServerClientName: snapshot.initialized.appServerClientName,
|
|
4054
|
+
clientVersion: snapshot.initialized.clientVersion,
|
|
4055
|
+
experimentalApiEnabled: snapshot.initialized.experimentalApiEnabled,
|
|
4056
|
+
optedOutNotificationMethods: new Set(
|
|
4057
|
+
snapshot.initialized.optedOutNotificationMethods
|
|
4058
|
+
)
|
|
4059
|
+
});
|
|
4060
|
+
}
|
|
4036
4061
|
};
|
|
4037
4062
|
var CODEX_APP_SERVER_DEFERRED_RESPONSE = {
|
|
4038
4063
|
__codexAppServerDeferredResponse: true
|
|
@@ -6477,8 +6502,7 @@ var WsStream = class {
|
|
|
6477
6502
|
waiters = [];
|
|
6478
6503
|
closed = false;
|
|
6479
6504
|
is_closed() {
|
|
6480
|
-
|
|
6481
|
-
return this.closed || this.socket.readyState === (closedState ?? 3);
|
|
6505
|
+
return this.closed || this.socket.readyState === 3;
|
|
6482
6506
|
}
|
|
6483
6507
|
send(message) {
|
|
6484
6508
|
if (this.is_closed()) {
|
|
@@ -6504,9 +6528,11 @@ var WsStream = class {
|
|
|
6504
6528
|
let timeout = null;
|
|
6505
6529
|
try {
|
|
6506
6530
|
return await Promise.race([
|
|
6507
|
-
new Promise(
|
|
6508
|
-
|
|
6509
|
-
|
|
6531
|
+
new Promise(
|
|
6532
|
+
(resolve, reject) => {
|
|
6533
|
+
this.waiters.push({ resolve, reject });
|
|
6534
|
+
}
|
|
6535
|
+
),
|
|
6510
6536
|
new Promise((_, reject) => {
|
|
6511
6537
|
if (timeoutMs && timeoutMs > 0) {
|
|
6512
6538
|
timeout = setTimeout(
|
|
@@ -6760,7 +6786,11 @@ function closeLikeEvent() {
|
|
|
6760
6786
|
reason: "websocket closed"
|
|
6761
6787
|
});
|
|
6762
6788
|
}
|
|
6763
|
-
return {
|
|
6789
|
+
return {
|
|
6790
|
+
type: "close",
|
|
6791
|
+
code: 1006,
|
|
6792
|
+
reason: "websocket closed"
|
|
6793
|
+
};
|
|
6764
6794
|
}
|
|
6765
6795
|
function isCloseEvent(event) {
|
|
6766
6796
|
return event.type === "close";
|
|
@@ -19851,8 +19881,8 @@ var ThreadStateManager = class {
|
|
|
19851
19881
|
}
|
|
19852
19882
|
};
|
|
19853
19883
|
|
|
19854
|
-
// src/internal/codex/app-server/src/
|
|
19855
|
-
function
|
|
19884
|
+
// src/internal/codex/app-server/src/app_server_event_mapping.ts
|
|
19885
|
+
function mapCoreEventToAppServerEvents(msg, context) {
|
|
19856
19886
|
return eventMsgToAppServerEvents(msg, context);
|
|
19857
19887
|
}
|
|
19858
19888
|
|
|
@@ -19884,7 +19914,11 @@ function createCodexAppServerRuntime(options) {
|
|
|
19884
19914
|
});
|
|
19885
19915
|
async function emit(threadId, event, context) {
|
|
19886
19916
|
if (event.type === "server_notification") {
|
|
19887
|
-
await outgoing.sendServerNotification(
|
|
19917
|
+
await outgoing.sendServerNotification(
|
|
19918
|
+
event.notification,
|
|
19919
|
+
context,
|
|
19920
|
+
threadId
|
|
19921
|
+
);
|
|
19888
19922
|
return;
|
|
19889
19923
|
}
|
|
19890
19924
|
if (event.type === "server_request") {
|
|
@@ -19913,7 +19947,7 @@ function createCodexAppServerRuntime(options) {
|
|
|
19913
19947
|
}
|
|
19914
19948
|
const threadState = threadStateManager.threadState(threadId);
|
|
19915
19949
|
const tracked = threadState.trackCurrentTurnEvent(event.id, event.msg);
|
|
19916
|
-
const protocolEvents =
|
|
19950
|
+
const protocolEvents = mapCoreEventToAppServerEvents(event.msg, {
|
|
19917
19951
|
activeTurn: tracked.activeTurn,
|
|
19918
19952
|
terminalTurn: tracked.terminalTurn,
|
|
19919
19953
|
threadId,
|
|
@@ -19992,9 +20026,7 @@ function createCodexAppServerRuntime(options) {
|
|
|
19992
20026
|
async function resolveServerRequest(params) {
|
|
19993
20027
|
const threadId = asThreadId(String(params.threadId));
|
|
19994
20028
|
const targetKey = serverRequestTargetKey(threadId, params.requestId);
|
|
19995
|
-
const request2 = outgoing.pendingRequestsForThread(threadId).find(
|
|
19996
|
-
(candidate) => candidate.id === params.requestId
|
|
19997
|
-
) ?? null;
|
|
20029
|
+
const request2 = outgoing.pendingRequestsForThread(threadId).find((candidate) => candidate.id === params.requestId) ?? null;
|
|
19998
20030
|
if (!request2) {
|
|
19999
20031
|
serverRequestTargets.delete(targetKey);
|
|
20000
20032
|
}
|
|
@@ -20008,10 +20040,13 @@ function createCodexAppServerRuntime(options) {
|
|
|
20008
20040
|
await submitServerRequestResponse(threadId, submission);
|
|
20009
20041
|
serverRequestTargets.delete(targetKey);
|
|
20010
20042
|
await outgoing.notifyClientResponse(params.requestId, params.result);
|
|
20011
|
-
await emit(
|
|
20012
|
-
|
|
20013
|
-
|
|
20014
|
-
|
|
20043
|
+
await emit(
|
|
20044
|
+
threadId,
|
|
20045
|
+
serverRequestResolvedNotification({
|
|
20046
|
+
requestId: params.requestId,
|
|
20047
|
+
threadId
|
|
20048
|
+
})
|
|
20049
|
+
);
|
|
20015
20050
|
}
|
|
20016
20051
|
async function connectionClosed(connectionId) {
|
|
20017
20052
|
const emptyThreadIds = threadStateManager.removeConnection(connectionId);
|
|
@@ -20026,9 +20061,7 @@ function createCodexAppServerRuntime(options) {
|
|
|
20026
20061
|
async function rejectServerRequest(params) {
|
|
20027
20062
|
const threadId = asThreadId(String(params.threadId));
|
|
20028
20063
|
const targetKey = serverRequestTargetKey(threadId, params.requestId);
|
|
20029
|
-
const request2 = outgoing.pendingRequestsForThread(threadId).find(
|
|
20030
|
-
(candidate) => candidate.id === params.requestId
|
|
20031
|
-
) ?? null;
|
|
20064
|
+
const request2 = outgoing.pendingRequestsForThread(threadId).find((candidate) => candidate.id === params.requestId) ?? null;
|
|
20032
20065
|
if (!request2) {
|
|
20033
20066
|
serverRequestTargets.delete(targetKey);
|
|
20034
20067
|
}
|
|
@@ -20042,18 +20075,25 @@ function createCodexAppServerRuntime(options) {
|
|
|
20042
20075
|
await submitServerRequestResponse(threadId, submission);
|
|
20043
20076
|
serverRequestTargets.delete(targetKey);
|
|
20044
20077
|
await outgoing.notifyClientError(params.requestId, params.error);
|
|
20045
|
-
await emit(
|
|
20046
|
-
|
|
20047
|
-
|
|
20048
|
-
|
|
20078
|
+
await emit(
|
|
20079
|
+
threadId,
|
|
20080
|
+
serverRequestResolvedNotification({
|
|
20081
|
+
requestId: params.requestId,
|
|
20082
|
+
threadId
|
|
20083
|
+
})
|
|
20084
|
+
);
|
|
20049
20085
|
}
|
|
20050
20086
|
async function submitServerRequestResponse(threadId, submission) {
|
|
20051
20087
|
if (!isServerRequestResponseSubmission(submission)) {
|
|
20052
|
-
throw new Error(
|
|
20088
|
+
throw new Error(
|
|
20089
|
+
"Only server-request response submissions can be routed through CodexAppServerRuntime."
|
|
20090
|
+
);
|
|
20053
20091
|
}
|
|
20054
20092
|
const runtimeSession = sessions.get(threadId);
|
|
20055
20093
|
if (!runtimeSession) {
|
|
20056
|
-
throw new Error(
|
|
20094
|
+
throw new Error(
|
|
20095
|
+
"Codex thread has no active turn for this server request response."
|
|
20096
|
+
);
|
|
20057
20097
|
}
|
|
20058
20098
|
await runtimeSession.session.submit_with_id(submission);
|
|
20059
20099
|
}
|
|
@@ -20485,4 +20525,437 @@ function dirname(path) {
|
|
|
20485
20525
|
return separatorIndex <= 0 ? "/" : normalized.slice(0, separatorIndex);
|
|
20486
20526
|
}
|
|
20487
20527
|
|
|
20488
|
-
|
|
20528
|
+
// src/server/dynamic-tools.ts
|
|
20529
|
+
var RESPONSES_API_TOOL_NAME = /^[A-Za-z0-9_-]+$/u;
|
|
20530
|
+
var RESPONSES_API_TOOL_NAME_MAX_LENGTH = 64;
|
|
20531
|
+
var dynamicToolResponse = {
|
|
20532
|
+
text(text) {
|
|
20533
|
+
return {
|
|
20534
|
+
contentItems: [{ text, type: "inputText" }],
|
|
20535
|
+
success: true
|
|
20536
|
+
};
|
|
20537
|
+
},
|
|
20538
|
+
image(imageUrl) {
|
|
20539
|
+
return {
|
|
20540
|
+
contentItems: [{ imageUrl, type: "inputImage" }],
|
|
20541
|
+
success: true
|
|
20542
|
+
};
|
|
20543
|
+
},
|
|
20544
|
+
error(message) {
|
|
20545
|
+
return {
|
|
20546
|
+
contentItems: [{ text: message, type: "inputText" }],
|
|
20547
|
+
success: false
|
|
20548
|
+
};
|
|
20549
|
+
}
|
|
20550
|
+
};
|
|
20551
|
+
function defineDynamicTool(definition) {
|
|
20552
|
+
const tool = Object.freeze({
|
|
20553
|
+
...definition,
|
|
20554
|
+
deferLoading: definition.deferLoading ?? false,
|
|
20555
|
+
namespace: definition.namespace ?? null
|
|
20556
|
+
});
|
|
20557
|
+
validateDynamicToolDefinitions([tool]);
|
|
20558
|
+
return tool;
|
|
20559
|
+
}
|
|
20560
|
+
function defineDynamicToolset(definitions) {
|
|
20561
|
+
const tools = definitions.map(
|
|
20562
|
+
(definition) => Object.freeze({
|
|
20563
|
+
...definition,
|
|
20564
|
+
deferLoading: definition.deferLoading ?? false,
|
|
20565
|
+
namespace: definition.namespace ?? null
|
|
20566
|
+
})
|
|
20567
|
+
);
|
|
20568
|
+
validateDynamicToolDefinitions(tools);
|
|
20569
|
+
return Object.freeze(tools);
|
|
20570
|
+
}
|
|
20571
|
+
function dynamicToolSpecFromDefinition(tool) {
|
|
20572
|
+
return {
|
|
20573
|
+
defer_loading: tool.deferLoading ?? false,
|
|
20574
|
+
description: tool.description,
|
|
20575
|
+
input_schema: tool.inputSchema,
|
|
20576
|
+
name: tool.name,
|
|
20577
|
+
namespace: tool.namespace ?? null
|
|
20578
|
+
};
|
|
20579
|
+
}
|
|
20580
|
+
function dynamicToolSpecsFromDefinitions(tools) {
|
|
20581
|
+
return tools.map(dynamicToolSpecFromDefinition);
|
|
20582
|
+
}
|
|
20583
|
+
function findDynamicTool(tools, params) {
|
|
20584
|
+
const namespace = params.namespace ?? null;
|
|
20585
|
+
return tools.find(
|
|
20586
|
+
(tool) => (tool.namespace ?? null) === namespace && tool.name === params.tool
|
|
20587
|
+
) ?? null;
|
|
20588
|
+
}
|
|
20589
|
+
function validateDynamicToolDefinitions(tools) {
|
|
20590
|
+
const names = /* @__PURE__ */ new Set();
|
|
20591
|
+
for (const tool of tools) {
|
|
20592
|
+
validateResponsesApiName(tool.name, "name");
|
|
20593
|
+
if (tool.namespace) {
|
|
20594
|
+
validateResponsesApiName(tool.namespace, "namespace");
|
|
20595
|
+
}
|
|
20596
|
+
if ((tool.deferLoading ?? false) && !tool.namespace) {
|
|
20597
|
+
throw new Error(
|
|
20598
|
+
`Dynamic tool ${tool.name} uses deferLoading and must include a namespace.`
|
|
20599
|
+
);
|
|
20600
|
+
}
|
|
20601
|
+
validateInputSchema(tool.name, tool.inputSchema);
|
|
20602
|
+
const key = `${tool.namespace ?? ""}:${tool.name}`;
|
|
20603
|
+
if (names.has(key)) {
|
|
20604
|
+
throw new Error(
|
|
20605
|
+
`Duplicate dynamic tool registration for ${tool.namespace ? `${tool.namespace}/` : ""}${tool.name}.`
|
|
20606
|
+
);
|
|
20607
|
+
}
|
|
20608
|
+
names.add(key);
|
|
20609
|
+
}
|
|
20610
|
+
}
|
|
20611
|
+
function validateResponsesApiName(value, label) {
|
|
20612
|
+
if (value.length === 0 || value.length > RESPONSES_API_TOOL_NAME_MAX_LENGTH || !RESPONSES_API_TOOL_NAME.test(value)) {
|
|
20613
|
+
throw new Error(
|
|
20614
|
+
`Dynamic tool ${label} ${value} is not supported by the Responses API. Tool names and namespaces may only contain letters, numbers, underscores, and hyphens.`
|
|
20615
|
+
);
|
|
20616
|
+
}
|
|
20617
|
+
}
|
|
20618
|
+
function validateInputSchema(toolName, schema) {
|
|
20619
|
+
if (!isRecord15(schema)) {
|
|
20620
|
+
throw new Error(
|
|
20621
|
+
`Dynamic tool ${toolName} inputSchema must be a JSON Schema object.`
|
|
20622
|
+
);
|
|
20623
|
+
}
|
|
20624
|
+
if (schema.type !== "object") {
|
|
20625
|
+
throw new Error(
|
|
20626
|
+
`Dynamic tool ${toolName} inputSchema must use type "object".`
|
|
20627
|
+
);
|
|
20628
|
+
}
|
|
20629
|
+
if ("properties" in schema && !isRecord15(schema.properties)) {
|
|
20630
|
+
throw new Error(
|
|
20631
|
+
`Dynamic tool ${toolName} inputSchema.properties must be an object when present.`
|
|
20632
|
+
);
|
|
20633
|
+
}
|
|
20634
|
+
if ("required" in schema && !isStringArray(schema.required)) {
|
|
20635
|
+
throw new Error(
|
|
20636
|
+
`Dynamic tool ${toolName} inputSchema.required must be a string array when present.`
|
|
20637
|
+
);
|
|
20638
|
+
}
|
|
20639
|
+
}
|
|
20640
|
+
function isRecord15(value) {
|
|
20641
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20642
|
+
}
|
|
20643
|
+
function isStringArray(value) {
|
|
20644
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
20645
|
+
}
|
|
20646
|
+
|
|
20647
|
+
// src/server/app-server.ts
|
|
20648
|
+
var nextConnectionId = 1;
|
|
20649
|
+
var InMemoryPendingServerRequestStore = class {
|
|
20650
|
+
records = /* @__PURE__ */ new Map();
|
|
20651
|
+
delete(requestId) {
|
|
20652
|
+
this.records.delete(requestId);
|
|
20653
|
+
}
|
|
20654
|
+
get(requestId) {
|
|
20655
|
+
return this.records.get(requestId) ?? null;
|
|
20656
|
+
}
|
|
20657
|
+
list() {
|
|
20658
|
+
return Array.from(this.records.values());
|
|
20659
|
+
}
|
|
20660
|
+
put(record) {
|
|
20661
|
+
this.records.set(record.requestId, record);
|
|
20662
|
+
}
|
|
20663
|
+
take(requestId) {
|
|
20664
|
+
const record = this.get(requestId);
|
|
20665
|
+
this.delete(requestId);
|
|
20666
|
+
return record;
|
|
20667
|
+
}
|
|
20668
|
+
};
|
|
20669
|
+
function createCodexAppServer(options) {
|
|
20670
|
+
const threadStore = options.threadStore ?? options.store;
|
|
20671
|
+
if (!threadStore) {
|
|
20672
|
+
throw new Error("createCodexAppServer requires threadStore.");
|
|
20673
|
+
}
|
|
20674
|
+
const dynamicTools = [...options.dynamicTools ?? []];
|
|
20675
|
+
const pendingServerRequests = options.pendingServerRequests ?? new InMemoryPendingServerRequestStore();
|
|
20676
|
+
const connections = /* @__PURE__ */ new Map();
|
|
20677
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
20678
|
+
const runtime = createCodexAppServerRuntime({
|
|
20679
|
+
...options,
|
|
20680
|
+
store: threadStore,
|
|
20681
|
+
buildCreateThreadParams: async (input) => {
|
|
20682
|
+
const base = options.buildCreateThreadParams ? await options.buildCreateThreadParams(input) : {
|
|
20683
|
+
base_instructions: {
|
|
20684
|
+
text: input.params.baseInstructions ?? options.defaults?.baseInstructions ?? BaseInstructions.default().text
|
|
20685
|
+
},
|
|
20686
|
+
dynamic_tools: [],
|
|
20687
|
+
event_persistence_mode: ThreadEventPersistenceMode.Limited,
|
|
20688
|
+
metadata: {
|
|
20689
|
+
cwd: input.params.cwd ?? options.defaults?.cwd ?? "/",
|
|
20690
|
+
memory_mode: ThreadMemoryMode.Disabled,
|
|
20691
|
+
model: input.params.model ?? options.defaults?.model ?? "gpt-5-mini",
|
|
20692
|
+
model_provider: input.params.modelProvider ?? options.defaults?.modelProvider ?? "openai"
|
|
20693
|
+
},
|
|
20694
|
+
source: options.defaults?.source ?? "appServer",
|
|
20695
|
+
thread_id: input.threadId,
|
|
20696
|
+
thread_source: typeof input.params.threadSource === "string" ? input.params.threadSource : options.defaults?.threadSource ?? null
|
|
20697
|
+
};
|
|
20698
|
+
const resolvedTools = (await options.resolveDynamicTools?.(input))?.map((tool) => tool) ?? [];
|
|
20699
|
+
return {
|
|
20700
|
+
...base,
|
|
20701
|
+
dynamic_tools: [
|
|
20702
|
+
...base.dynamic_tools ?? [],
|
|
20703
|
+
...resolvedTools,
|
|
20704
|
+
...dynamicTools.map(dynamicToolSpecFromDefinition)
|
|
20705
|
+
]
|
|
20706
|
+
};
|
|
20707
|
+
},
|
|
20708
|
+
buildSessionConfiguration: async (input) => {
|
|
20709
|
+
const config = await options.buildSessionConfiguration?.(input) ?? {};
|
|
20710
|
+
return {
|
|
20711
|
+
...config,
|
|
20712
|
+
dynamic_tools: [
|
|
20713
|
+
...config.dynamic_tools ?? [],
|
|
20714
|
+
...dynamicTools.map(dynamicToolSpecFromDefinition)
|
|
20715
|
+
]
|
|
20716
|
+
};
|
|
20717
|
+
},
|
|
20718
|
+
sendOutgoingTransportMessage: async (message, messageContext) => {
|
|
20719
|
+
const handled = await maybeExecuteDynamicTool({
|
|
20720
|
+
context: messageContext.context,
|
|
20721
|
+
dynamicTools,
|
|
20722
|
+
message,
|
|
20723
|
+
runtime,
|
|
20724
|
+
threadId: messageContext.threadId
|
|
20725
|
+
});
|
|
20726
|
+
if (handled) {
|
|
20727
|
+
return;
|
|
20728
|
+
}
|
|
20729
|
+
if (isServerRequest2(message)) {
|
|
20730
|
+
const threadId = messageContext.threadId ?? serverRequestThreadId(message);
|
|
20731
|
+
if (threadId) {
|
|
20732
|
+
await pendingServerRequests.put({
|
|
20733
|
+
createdAt: Date.now(),
|
|
20734
|
+
request: message,
|
|
20735
|
+
requestId: message.id,
|
|
20736
|
+
threadId: String(threadId)
|
|
20737
|
+
});
|
|
20738
|
+
}
|
|
20739
|
+
}
|
|
20740
|
+
await sendToConnections({
|
|
20741
|
+
connectionIds: messageContext.connectionIds,
|
|
20742
|
+
connections,
|
|
20743
|
+
message,
|
|
20744
|
+
subscriptions,
|
|
20745
|
+
threadId: messageContext.threadId
|
|
20746
|
+
});
|
|
20747
|
+
}
|
|
20748
|
+
});
|
|
20749
|
+
function createConnection(connectionOptions) {
|
|
20750
|
+
const connectionId = connectionOptions.connectionId ?? nextConnectionId++;
|
|
20751
|
+
const session = CodexAppServerConnectionSessionState.fromSnapshot(
|
|
20752
|
+
connectionOptions.snapshot
|
|
20753
|
+
);
|
|
20754
|
+
const processor = runtime.createMessageProcessor({
|
|
20755
|
+
connectionId,
|
|
20756
|
+
session
|
|
20757
|
+
});
|
|
20758
|
+
connections.set(connectionId, {
|
|
20759
|
+
context: connectionOptions.context,
|
|
20760
|
+
send: connectionOptions.send
|
|
20761
|
+
});
|
|
20762
|
+
if (session.initialized()) {
|
|
20763
|
+
runtime.connectionInitialized(connectionId);
|
|
20764
|
+
}
|
|
20765
|
+
async function persistSnapshot() {
|
|
20766
|
+
await connectionOptions.onSnapshot?.(processor.session.snapshot());
|
|
20767
|
+
}
|
|
20768
|
+
return {
|
|
20769
|
+
async accept(message) {
|
|
20770
|
+
const parsed = parseServerTransportPayload(message);
|
|
20771
|
+
if (parsed.type === "invalid") {
|
|
20772
|
+
await connectionOptions.send(
|
|
20773
|
+
serializeJsonRpcError(parsed.id, parsed.error)
|
|
20774
|
+
);
|
|
20775
|
+
return;
|
|
20776
|
+
}
|
|
20777
|
+
switch (parsed.message.type) {
|
|
20778
|
+
case "client_request": {
|
|
20779
|
+
subscribeFromClientRequest(
|
|
20780
|
+
subscriptions,
|
|
20781
|
+
connectionId,
|
|
20782
|
+
parsed.message.request
|
|
20783
|
+
);
|
|
20784
|
+
const outcome = await processor.processConnectionRequest(
|
|
20785
|
+
parsed.message.request,
|
|
20786
|
+
connectionOptions.context
|
|
20787
|
+
);
|
|
20788
|
+
if (parsed.message.request.method === "initialize") {
|
|
20789
|
+
runtime.connectionInitialized(connectionId);
|
|
20790
|
+
}
|
|
20791
|
+
if (outcome.type === "response") {
|
|
20792
|
+
subscribeFromResult(subscriptions, connectionId, outcome.result);
|
|
20793
|
+
}
|
|
20794
|
+
await persistSnapshot();
|
|
20795
|
+
return;
|
|
20796
|
+
}
|
|
20797
|
+
case "response": {
|
|
20798
|
+
const pending = await pendingServerRequests.take(
|
|
20799
|
+
parsed.message.response.id
|
|
20800
|
+
);
|
|
20801
|
+
if (pending) {
|
|
20802
|
+
await runtime.resolveServerRequest(
|
|
20803
|
+
{
|
|
20804
|
+
requestId: parsed.message.response.id,
|
|
20805
|
+
result: parsed.message.response.result,
|
|
20806
|
+
threadId: pending.threadId
|
|
20807
|
+
},
|
|
20808
|
+
connectionOptions.context
|
|
20809
|
+
);
|
|
20810
|
+
}
|
|
20811
|
+
await persistSnapshot();
|
|
20812
|
+
return;
|
|
20813
|
+
}
|
|
20814
|
+
case "error": {
|
|
20815
|
+
if (parsed.message.error.id !== null) {
|
|
20816
|
+
const pending = await pendingServerRequests.take(
|
|
20817
|
+
parsed.message.error.id
|
|
20818
|
+
);
|
|
20819
|
+
if (pending) {
|
|
20820
|
+
await runtime.rejectServerRequest(
|
|
20821
|
+
{
|
|
20822
|
+
error: parsed.message.error.error,
|
|
20823
|
+
requestId: parsed.message.error.id,
|
|
20824
|
+
threadId: pending.threadId
|
|
20825
|
+
},
|
|
20826
|
+
connectionOptions.context
|
|
20827
|
+
);
|
|
20828
|
+
}
|
|
20829
|
+
}
|
|
20830
|
+
await persistSnapshot();
|
|
20831
|
+
return;
|
|
20832
|
+
}
|
|
20833
|
+
case "client_notification":
|
|
20834
|
+
await persistSnapshot();
|
|
20835
|
+
return;
|
|
20836
|
+
}
|
|
20837
|
+
},
|
|
20838
|
+
async close() {
|
|
20839
|
+
connections.delete(connectionId);
|
|
20840
|
+
for (const connectionIds of subscriptions.values()) {
|
|
20841
|
+
connectionIds.delete(connectionId);
|
|
20842
|
+
}
|
|
20843
|
+
await processor.connectionClosed();
|
|
20844
|
+
await runtime.connectionClosed(connectionId);
|
|
20845
|
+
},
|
|
20846
|
+
connectionId,
|
|
20847
|
+
processor,
|
|
20848
|
+
snapshot() {
|
|
20849
|
+
return processor.session.snapshot();
|
|
20850
|
+
}
|
|
20851
|
+
};
|
|
20852
|
+
}
|
|
20853
|
+
return Object.assign(runtime, {
|
|
20854
|
+
createConnection,
|
|
20855
|
+
pendingServerRequests
|
|
20856
|
+
});
|
|
20857
|
+
}
|
|
20858
|
+
function createCodexAppServerConnection(appServer, options) {
|
|
20859
|
+
return appServer.createConnection(options);
|
|
20860
|
+
}
|
|
20861
|
+
async function maybeExecuteDynamicTool(input) {
|
|
20862
|
+
if (!isDynamicToolCallRequest(input.message) || !input.threadId) {
|
|
20863
|
+
return false;
|
|
20864
|
+
}
|
|
20865
|
+
const params = input.message.params;
|
|
20866
|
+
const tool = findDynamicTool(input.dynamicTools, params);
|
|
20867
|
+
if (!tool?.execute) {
|
|
20868
|
+
return false;
|
|
20869
|
+
}
|
|
20870
|
+
try {
|
|
20871
|
+
const result = await tool.execute(params.arguments, {
|
|
20872
|
+
callId: params.callId,
|
|
20873
|
+
context: input.context,
|
|
20874
|
+
namespace: params.namespace ?? null,
|
|
20875
|
+
params,
|
|
20876
|
+
threadId: params.threadId,
|
|
20877
|
+
tool: params.tool,
|
|
20878
|
+
turnId: params.turnId
|
|
20879
|
+
});
|
|
20880
|
+
await input.runtime.resolveServerRequest(
|
|
20881
|
+
{
|
|
20882
|
+
requestId: input.message.id,
|
|
20883
|
+
result,
|
|
20884
|
+
threadId: input.threadId
|
|
20885
|
+
},
|
|
20886
|
+
input.context
|
|
20887
|
+
);
|
|
20888
|
+
} catch (error) {
|
|
20889
|
+
await input.runtime.resolveServerRequest(
|
|
20890
|
+
{
|
|
20891
|
+
requestId: input.message.id,
|
|
20892
|
+
result: dynamicToolResponse.error(
|
|
20893
|
+
error instanceof Error ? error.message : "Dynamic tool failed."
|
|
20894
|
+
),
|
|
20895
|
+
threadId: input.threadId
|
|
20896
|
+
},
|
|
20897
|
+
input.context
|
|
20898
|
+
);
|
|
20899
|
+
}
|
|
20900
|
+
return true;
|
|
20901
|
+
}
|
|
20902
|
+
async function sendToConnections(input) {
|
|
20903
|
+
const payload = serializeOutgoingMessage(input.message);
|
|
20904
|
+
const recipients = recipientConnectionIds(input);
|
|
20905
|
+
await Promise.all(
|
|
20906
|
+
recipients.map(async (connectionId) => {
|
|
20907
|
+
const connection = input.connections.get(connectionId);
|
|
20908
|
+
if (connection) {
|
|
20909
|
+
await connection.send(payload);
|
|
20910
|
+
}
|
|
20911
|
+
})
|
|
20912
|
+
);
|
|
20913
|
+
}
|
|
20914
|
+
function recipientConnectionIds(input) {
|
|
20915
|
+
if (input.connectionIds?.length) {
|
|
20916
|
+
return input.connectionIds;
|
|
20917
|
+
}
|
|
20918
|
+
if (input.threadId) {
|
|
20919
|
+
return Array.from(input.subscriptions.get(String(input.threadId)) ?? []);
|
|
20920
|
+
}
|
|
20921
|
+
return Array.from(input.connections.keys());
|
|
20922
|
+
}
|
|
20923
|
+
function subscribeFromClientRequest(subscriptions, connectionId, request2) {
|
|
20924
|
+
const params = request2.params;
|
|
20925
|
+
const threadId = typeof params?.threadId === "string" ? params.threadId : typeof params?.thread_id === "string" ? params.thread_id : null;
|
|
20926
|
+
if (threadId) {
|
|
20927
|
+
subscribe(subscriptions, connectionId, threadId);
|
|
20928
|
+
}
|
|
20929
|
+
}
|
|
20930
|
+
function subscribeFromResult(subscriptions, connectionId, result) {
|
|
20931
|
+
const threadId = result?.thread?.id;
|
|
20932
|
+
if (typeof threadId === "string") {
|
|
20933
|
+
subscribe(subscriptions, connectionId, threadId);
|
|
20934
|
+
}
|
|
20935
|
+
}
|
|
20936
|
+
function subscribe(subscriptions, connectionId, threadId) {
|
|
20937
|
+
const connectionIds = subscriptions.get(threadId) ?? /* @__PURE__ */ new Set();
|
|
20938
|
+
connectionIds.add(connectionId);
|
|
20939
|
+
subscriptions.set(threadId, connectionIds);
|
|
20940
|
+
}
|
|
20941
|
+
function isServerRequest2(message) {
|
|
20942
|
+
return "method" in message && "id" in message;
|
|
20943
|
+
}
|
|
20944
|
+
function isDynamicToolCallRequest(message) {
|
|
20945
|
+
return isServerRequest2(message) && message.method === "item/tool/call";
|
|
20946
|
+
}
|
|
20947
|
+
function jsonRpcErrorFromUnknown2(error) {
|
|
20948
|
+
if (typeof error === "object" && error !== null && "code" in error && "message" in error && typeof error.code === "number" && typeof error.message === "string") {
|
|
20949
|
+
return error;
|
|
20950
|
+
}
|
|
20951
|
+
const nested = error?.error;
|
|
20952
|
+
if (typeof nested === "object" && nested !== null && "code" in nested && "message" in nested && typeof nested.code === "number" && typeof nested.message === "string") {
|
|
20953
|
+
return nested;
|
|
20954
|
+
}
|
|
20955
|
+
return {
|
|
20956
|
+
code: error instanceof CodexAppServerRequestError ? error.error.code : -32e3,
|
|
20957
|
+
message: error instanceof Error ? error.message : "Codex request failed."
|
|
20958
|
+
};
|
|
20959
|
+
}
|
|
20960
|
+
|
|
20961
|
+
export { AppServerSession, BaseInstructions, CodexAppServerClientTransportError, CodexAppServerConnectionSessionState, CodexAppServerMessageProcessor, CodexAppServerRequestError, CodexMcpConnectionManagerAdapter, ConnectionRpcGate, ConnectionRpcGateClosedError, EmptyMcpConnectionManager, InMemoryPendingServerRequestStore, InMemoryThreadStore, LiveThread, LocalThreadStore, McpRequestProcessor, ModelClientSession, OutgoingMessageSender, PendingAppServerRequests, RequestSerializationQueues, ResponsesClient, ResponsesWebsocketClient, ResponsesWebsocketConnection, SortDirection, StaticMcpConnectionManager, ThreadEventPersistenceMode, ThreadEventStore, ThreadHistoryBuilder, ThreadMemoryMode, ThreadRequestProcessor, ThreadScopedOutgoingMessageSender, ThreadSortKey, TurnRequestProcessor, asThreadId, codexAppServerDeferredResponse, dynamicToolResponse as codexDynamicToolResponse, createCodexAppServer, createCodexAppServerClient, createCodexAppServerConnection, createCodexAppServerRuntime, createModelClient, defineDynamicTool as defineCodexDynamicTool, defineDynamicToolset as defineCodexDynamicToolset, defineDynamicTool, defineDynamicToolset, deniedRequestPermissionsResponse, dynamicToolResponse, dynamicToolSpecFromDefinition, dynamicToolSpecsFromDefinitions, findDynamicTool, jsonRpcErrorFromUnknown2 as jsonRpcErrorFromUnknown, jsonRpcInternalError, jsonRpcInvalidRequestError, jsonRpcParseError, outgoingMessageToAppServerEvent, parseClientTransportPayload, parseCodexAppServerEvent, parseJsonRpcMessage, parseJsonRpcTransportPayload, parseServerTransportPayload, queuedOutgoingMessage, requestMethodName, requestSerializationQueueKeyFromScope, requestTyped, serializeJsonRpcError, serializeJsonRpcResponse, serializeOutgoingMessage, serverNotificationRequiresDelivery, serverNotificationThreadTarget, serverRequestThreadId, setRenderedThreadConnectionStatus, threadEventSnapshotHasStarted, validateDynamicToolDefinitions };
|