@realtimex/sdk 1.3.5-rc.1 → 1.3.5-rc.2

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/dist/index.js CHANGED
@@ -30,6 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ACPContractAdapter: () => ACPContractAdapter,
34
+ ACPEventMapper: () => ACPEventMapper,
35
+ ACPPermissionBridge: () => ACPPermissionBridge,
36
+ ACPTelemetry: () => ACPTelemetry,
33
37
  ActivitiesModule: () => ActivitiesModule,
34
38
  AgentModule: () => AgentModule,
35
39
  ApiModule: () => ApiModule,
@@ -37,7 +41,16 @@ __export(index_exports, {
37
41
  CONTRACT_EVENT_ID_HEADER: () => CONTRACT_EVENT_ID_HEADER,
38
42
  CONTRACT_SIGNATURE_ALGORITHM: () => CONTRACT_SIGNATURE_ALGORITHM,
39
43
  CONTRACT_SIGNATURE_HEADER: () => CONTRACT_SIGNATURE_HEADER,
44
+ ClaudeToolAdapter: () => ClaudeToolAdapter,
45
+ CodexToolAdapter: () => CodexToolAdapter,
46
+ ContractCache: () => ContractCache,
47
+ ContractClient: () => ContractClient,
48
+ ContractError: () => ContractError,
49
+ ContractHttpClient: () => ContractHttpClient,
40
50
  ContractModule: () => ContractModule,
51
+ ContractRuntime: () => ContractRuntime,
52
+ ContractValidationError: () => ContractValidationError,
53
+ GeminiToolAdapter: () => GeminiToolAdapter,
41
54
  LLMModule: () => LLMModule,
42
55
  LLMPermissionError: () => LLMPermissionError,
43
56
  LLMProviderError: () => LLMProviderError,
@@ -47,9 +60,17 @@ __export(index_exports, {
47
60
  PermissionRequiredError: () => PermissionRequiredError,
48
61
  PortModule: () => PortModule,
49
62
  RealtimeXSDK: () => RealtimeXSDK,
63
+ RetryPolicy: () => RetryPolicy,
64
+ RuntimeTransportError: () => RuntimeTransportError,
50
65
  STTModule: () => STTModule,
66
+ ScopeDeniedError: () => ScopeDeniedError,
67
+ ScopeGuard: () => ScopeGuard,
68
+ StaticAuthProvider: () => StaticAuthProvider,
51
69
  TTSModule: () => TTSModule,
52
70
  TaskModule: () => TaskModule,
71
+ ToolNotFoundError: () => ToolNotFoundError,
72
+ ToolProjector: () => ToolProjector,
73
+ ToolValidationError: () => ToolValidationError,
53
74
  VectorStore: () => VectorStore,
54
75
  WebhookModule: () => WebhookModule,
55
76
  buildContractIdempotencyKey: () => buildContractIdempotencyKey,
@@ -59,8 +80,11 @@ __export(index_exports, {
59
80
  hashContractPayload: () => hashContractPayload,
60
81
  normalizeAttemptId: () => normalizeAttemptId,
61
82
  normalizeContractEvent: () => normalizeContractEvent,
83
+ normalizeLocalAppContractV1: () => normalizeLocalAppContractV1,
84
+ normalizeSchema: () => normalizeSchema,
62
85
  parseAttemptRunId: () => parseAttemptRunId,
63
- signContractEvent: () => signContractEvent
86
+ signContractEvent: () => signContractEvent,
87
+ toStableToolName: () => toStableToolName
64
88
  });
65
89
  module.exports = __toCommonJS(index_exports);
66
90
 
@@ -1779,6 +1803,1485 @@ var HttpClient = class {
1779
1803
  }
1780
1804
  };
1781
1805
 
1806
+ // src/core/errors/ContractErrors.ts
1807
+ var ContractError = class extends Error {
1808
+ constructor(code, message, details) {
1809
+ super(message);
1810
+ this.name = this.constructor.name;
1811
+ this.code = code;
1812
+ this.details = details;
1813
+ }
1814
+ };
1815
+ var ContractValidationError = class extends ContractError {
1816
+ constructor(message, details) {
1817
+ super("contract_validation_error", message, details);
1818
+ }
1819
+ };
1820
+ var ToolValidationError = class extends ContractError {
1821
+ constructor(message, details) {
1822
+ super("tool_validation_error", message, details);
1823
+ }
1824
+ };
1825
+ var ToolNotFoundError = class extends ContractError {
1826
+ constructor(toolName, details) {
1827
+ super("tool_not_found", `Tool not found: ${toolName}`, details);
1828
+ }
1829
+ };
1830
+ var ScopeDeniedError = class extends ContractError {
1831
+ constructor(permission, details) {
1832
+ super("scope_denied", `Missing required permission: ${permission}`, details);
1833
+ }
1834
+ };
1835
+ var RuntimeTransportError = class extends ContractError {
1836
+ constructor(message, statusCode, details) {
1837
+ super("runtime_transport_error", message, details);
1838
+ this.statusCode = statusCode;
1839
+ }
1840
+ };
1841
+
1842
+ // src/core/auth/ScopeGuard.ts
1843
+ var ScopeGuard = class {
1844
+ constructor(scopes = []) {
1845
+ this.scopes = new Set(scopes.filter((scope) => scope.trim().length > 0));
1846
+ }
1847
+ can(permission) {
1848
+ if (!permission) return true;
1849
+ if (this.scopes.size === 0) return true;
1850
+ return this.scopes.has(permission);
1851
+ }
1852
+ assert(permission) {
1853
+ if (!permission) return;
1854
+ if (!this.can(permission)) {
1855
+ throw new ScopeDeniedError(permission);
1856
+ }
1857
+ }
1858
+ };
1859
+
1860
+ // src/core/contract/ContractCache.ts
1861
+ var ContractCache = class {
1862
+ constructor(ttlMs = 3e4) {
1863
+ this.entries = /* @__PURE__ */ new Map();
1864
+ this.ttlMs = ttlMs > 0 ? ttlMs : null;
1865
+ }
1866
+ get(key) {
1867
+ const entry = this.entries.get(key);
1868
+ if (!entry) return null;
1869
+ if (entry.expiresAt !== null && entry.expiresAt <= Date.now()) {
1870
+ this.entries.delete(key);
1871
+ return null;
1872
+ }
1873
+ return entry.value;
1874
+ }
1875
+ set(key, value) {
1876
+ const expiresAt = this.ttlMs === null ? null : Date.now() + this.ttlMs;
1877
+ this.entries.set(key, { value, expiresAt });
1878
+ }
1879
+ clear(key) {
1880
+ if (key) {
1881
+ this.entries.delete(key);
1882
+ return;
1883
+ }
1884
+ this.entries.clear();
1885
+ }
1886
+ };
1887
+
1888
+ // src/core/contract/ContractValidator.ts
1889
+ var LOCAL_APP_CONTRACT_VERSION2 = "local-app-contract/v1";
1890
+ var DEFAULT_SUPPORTED_EVENTS = [
1891
+ "task.trigger",
1892
+ "system.ping",
1893
+ "task.claimed",
1894
+ "task.started",
1895
+ "task.progress",
1896
+ "task.completed",
1897
+ "task.failed",
1898
+ "task.canceled"
1899
+ ];
1900
+ function isRecord(value) {
1901
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1902
+ }
1903
+ function asStringArray(value) {
1904
+ if (!Array.isArray(value)) return [];
1905
+ return value.filter((item) => typeof item === "string" && item.trim().length > 0);
1906
+ }
1907
+ function asStringRecord(value) {
1908
+ if (!isRecord(value)) return void 0;
1909
+ const entries = Object.entries(value).filter(
1910
+ ([key, item]) => key.trim().length > 0 && typeof item === "string"
1911
+ );
1912
+ if (entries.length === 0) return void 0;
1913
+ return entries.reduce((accumulator, [key, item]) => {
1914
+ accumulator[key] = item;
1915
+ return accumulator;
1916
+ }, {});
1917
+ }
1918
+ function normalizeStrictness(value) {
1919
+ return value === "strict" ? "strict" : "compatible";
1920
+ }
1921
+ function normalizeCallbackRules(value) {
1922
+ if (!isRecord(value)) return void 0;
1923
+ const callback = {};
1924
+ if (typeof value.event_id_header === "string") callback.event_id_header = value.event_id_header;
1925
+ if (typeof value.signature_header === "string") callback.signature_header = value.signature_header;
1926
+ if (typeof value.signature_algorithm === "string") callback.signature_algorithm = value.signature_algorithm;
1927
+ if (typeof value.signature_message === "string") callback.signature_message = value.signature_message;
1928
+ if (typeof value.attempt_id_format === "string") callback.attempt_id_format = value.attempt_id_format;
1929
+ if (typeof value.idempotency === "string") callback.idempotency = value.idempotency;
1930
+ return Object.keys(callback).length > 0 ? callback : void 0;
1931
+ }
1932
+ function normalizeTrigger(value) {
1933
+ if (!isRecord(value)) {
1934
+ return { event: "task.trigger" };
1935
+ }
1936
+ const event = value.event === "task.trigger" ? "task.trigger" : "task.trigger";
1937
+ const route = typeof value.route === "string" && value.route.trim().length > 0 ? value.route : void 0;
1938
+ const payloadTemplate = isRecord(value.payload_template) ? value.payload_template : void 0;
1939
+ return {
1940
+ event,
1941
+ route,
1942
+ payload_template: payloadTemplate
1943
+ };
1944
+ }
1945
+ function normalizeCapability(value) {
1946
+ if (!isRecord(value)) {
1947
+ throw new ContractValidationError("Invalid capability: expected object");
1948
+ }
1949
+ const capabilityId = typeof value.capability_id === "string" ? value.capability_id.trim() : "";
1950
+ const name = typeof value.name === "string" ? value.name.trim() : "";
1951
+ const description = typeof value.description === "string" ? value.description.trim() : "";
1952
+ const permission = typeof value.permission === "string" ? value.permission.trim() : "";
1953
+ if (!capabilityId || !name || !description || !permission) {
1954
+ throw new ContractValidationError("Invalid capability: missing required fields", { capability: value });
1955
+ }
1956
+ if (!isRecord(value.input_schema)) {
1957
+ throw new ContractValidationError("Invalid capability input_schema: expected JSON schema object", {
1958
+ capability_id: capabilityId
1959
+ });
1960
+ }
1961
+ return {
1962
+ capability_id: capabilityId,
1963
+ name,
1964
+ description,
1965
+ input_schema: value.input_schema,
1966
+ output_schema: isRecord(value.output_schema) ? value.output_schema : void 0,
1967
+ permission,
1968
+ trigger: normalizeTrigger(value.trigger)
1969
+ };
1970
+ }
1971
+ function normalizeCapabilities(value) {
1972
+ if (value === void 0 || value === null) return void 0;
1973
+ if (!Array.isArray(value)) {
1974
+ throw new ContractValidationError("Invalid capabilities: expected array");
1975
+ }
1976
+ return value.map(normalizeCapability);
1977
+ }
1978
+ function extractContractRecord(payload) {
1979
+ if (!isRecord(payload)) {
1980
+ throw new ContractValidationError("Invalid contract response: expected object payload");
1981
+ }
1982
+ if (isRecord(payload.contract)) {
1983
+ return payload.contract;
1984
+ }
1985
+ return payload;
1986
+ }
1987
+ function resolveContractVersion(contract) {
1988
+ if (typeof contract.contract_version === "string") return contract.contract_version;
1989
+ if (typeof contract.version === "string") return contract.version;
1990
+ if (typeof contract.id === "string") return contract.id;
1991
+ return "";
1992
+ }
1993
+ function normalizeLocalAppContractV1(payload) {
1994
+ const contract = extractContractRecord(payload);
1995
+ const version = resolveContractVersion(contract);
1996
+ if (!version) {
1997
+ throw new ContractValidationError("Missing contract version in discovery response");
1998
+ }
1999
+ if (version !== LOCAL_APP_CONTRACT_VERSION2) {
2000
+ throw new ContractValidationError("Unsupported contract version", {
2001
+ expected: LOCAL_APP_CONTRACT_VERSION2,
2002
+ received: version
2003
+ });
2004
+ }
2005
+ const supportedContractEvents = asStringArray(contract.supported_contract_events).length > 0 ? asStringArray(contract.supported_contract_events) : asStringArray(contract.supported_events).length > 0 ? asStringArray(contract.supported_events) : DEFAULT_SUPPORTED_EVENTS;
2006
+ return {
2007
+ contract_version: LOCAL_APP_CONTRACT_VERSION2,
2008
+ strictness: normalizeStrictness(contract.strictness),
2009
+ supported_contract_events: supportedContractEvents,
2010
+ supported_legacy_events: asStringArray(contract.supported_legacy_events),
2011
+ aliases: asStringRecord(contract.aliases),
2012
+ status_map: asStringRecord(contract.status_map),
2013
+ legacy_action_map: asStringRecord(contract.legacy_action_map),
2014
+ callback: normalizeCallbackRules(contract.callback),
2015
+ capabilities: normalizeCapabilities(contract.capabilities)
2016
+ };
2017
+ }
2018
+
2019
+ // src/core/contract/ContractClient.ts
2020
+ var ContractClient = class {
2021
+ constructor(httpClient, options = {}) {
2022
+ this.httpClient = httpClient;
2023
+ this.cache = options.cache || new ContractCache();
2024
+ this.cacheKey = options.cacheKey || "local-app-contract/v1";
2025
+ }
2026
+ async getLocalAppV1(forceRefresh = false) {
2027
+ if (!forceRefresh) {
2028
+ const cached = this.cache.get(this.cacheKey);
2029
+ if (cached) return cached;
2030
+ }
2031
+ const response = await this.httpClient.get("/contracts/local-app/v1");
2032
+ const normalized = normalizeLocalAppContractV1(response);
2033
+ this.cache.set(this.cacheKey, normalized);
2034
+ return normalized;
2035
+ }
2036
+ clearCache() {
2037
+ this.cache.clear(this.cacheKey);
2038
+ }
2039
+ };
2040
+
2041
+ // src/core/transport/HttpClient.ts
2042
+ function toRecordHeaders(input = {}) {
2043
+ if (input instanceof Headers) {
2044
+ const normalized = {};
2045
+ input.forEach((value, key) => {
2046
+ normalized[key] = value;
2047
+ });
2048
+ return normalized;
2049
+ }
2050
+ if (Array.isArray(input)) {
2051
+ return Object.fromEntries(input);
2052
+ }
2053
+ return { ...input };
2054
+ }
2055
+ var ContractHttpClient = class {
2056
+ constructor(config) {
2057
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
2058
+ this.appId = config.appId;
2059
+ this.appName = config.appName;
2060
+ this.apiKey = config.apiKey;
2061
+ this.fetchImpl = config.fetchImpl || fetch;
2062
+ }
2063
+ async get(path, headers = {}) {
2064
+ return this.request(path, {
2065
+ method: "GET",
2066
+ headers
2067
+ });
2068
+ }
2069
+ async post(path, body, headers = {}) {
2070
+ return this.request(path, {
2071
+ method: "POST",
2072
+ headers,
2073
+ body: JSON.stringify(body)
2074
+ });
2075
+ }
2076
+ async request(path, options = {}) {
2077
+ const url = `${this.baseUrl}${path}`;
2078
+ const headers = this.buildHeaders(options.headers);
2079
+ let response;
2080
+ try {
2081
+ response = await this.fetchImpl(url, {
2082
+ ...options,
2083
+ headers
2084
+ });
2085
+ } catch (error) {
2086
+ throw new RuntimeTransportError("Failed to reach RealtimeX server", void 0, {
2087
+ cause: error,
2088
+ url
2089
+ });
2090
+ }
2091
+ const payload = await this.parseResponse(response);
2092
+ if (!response.ok) {
2093
+ const errorMessage = payload && typeof payload === "object" && "error" in payload && typeof payload.error === "string" ? payload.error : `Request failed with status ${response.status}`;
2094
+ throw new RuntimeTransportError(errorMessage, response.status, payload);
2095
+ }
2096
+ return payload;
2097
+ }
2098
+ buildHeaders(extraHeaders = {}) {
2099
+ const headers = {
2100
+ "Content-Type": "application/json",
2101
+ ...toRecordHeaders(extraHeaders)
2102
+ };
2103
+ if (this.apiKey) {
2104
+ headers.Authorization = `Bearer ${this.apiKey}`;
2105
+ }
2106
+ if (this.appId) {
2107
+ headers["x-app-id"] = this.appId;
2108
+ }
2109
+ if (this.appName) {
2110
+ headers["x-app-name"] = this.appName;
2111
+ }
2112
+ return headers;
2113
+ }
2114
+ async parseResponse(response) {
2115
+ const contentType = response.headers.get("content-type") || "";
2116
+ if (contentType.includes("application/json")) {
2117
+ try {
2118
+ return await response.json();
2119
+ } catch {
2120
+ return {};
2121
+ }
2122
+ }
2123
+ const text = await response.text();
2124
+ if (!text) return {};
2125
+ try {
2126
+ return JSON.parse(text);
2127
+ } catch {
2128
+ return { text };
2129
+ }
2130
+ }
2131
+ };
2132
+
2133
+ // src/core/tooling/SchemaNormalizer.ts
2134
+ function isRecord2(value) {
2135
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2136
+ }
2137
+ function deepClone(value) {
2138
+ return JSON.parse(JSON.stringify(value));
2139
+ }
2140
+ function normalizeSchema(schema) {
2141
+ if (!schema || !isRecord2(schema)) {
2142
+ return {
2143
+ type: "object",
2144
+ properties: {},
2145
+ additionalProperties: true
2146
+ };
2147
+ }
2148
+ const normalized = deepClone(schema);
2149
+ if (typeof normalized.type !== "string" && !Array.isArray(normalized.type)) {
2150
+ normalized.type = "object";
2151
+ }
2152
+ if (normalized.type === "object" && !isRecord2(normalized.properties)) {
2153
+ normalized.properties = {};
2154
+ }
2155
+ if (Array.isArray(normalized.required)) {
2156
+ normalized.required = normalized.required.filter(
2157
+ (field) => typeof field === "string" && field.trim().length > 0
2158
+ );
2159
+ }
2160
+ return normalized;
2161
+ }
2162
+
2163
+ // src/core/tooling/ToolNamePolicy.ts
2164
+ function normalizeToken(value) {
2165
+ return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
2166
+ }
2167
+ function toStableToolName(capabilityId, namespace) {
2168
+ const normalizedCapability = normalizeToken(capabilityId.replace(/\./g, "_"));
2169
+ const normalizedNamespace = namespace ? normalizeToken(namespace) : "";
2170
+ if (!normalizedCapability) {
2171
+ return normalizedNamespace ? `${normalizedNamespace}_tool` : "tool";
2172
+ }
2173
+ const combined = normalizedNamespace && !normalizedCapability.startsWith(`${normalizedNamespace}_`) ? `${normalizedNamespace}_${normalizedCapability}` : normalizedCapability;
2174
+ return /^[a-z]/.test(combined) ? combined : `tool_${combined}`;
2175
+ }
2176
+
2177
+ // src/core/tooling/ToolProjector.ts
2178
+ var ToolProjector = class {
2179
+ project(input) {
2180
+ const capabilities = input.contract.capabilities || [];
2181
+ const names = /* @__PURE__ */ new Set();
2182
+ return capabilities.map((capability) => {
2183
+ const baseName = toStableToolName(capability.capability_id, input.namespace || input.appId);
2184
+ const uniqueName = this.ensureUniqueToolName(baseName, names);
2185
+ return {
2186
+ tool_name: uniqueName,
2187
+ title: capability.name,
2188
+ description: capability.description,
2189
+ input_schema: normalizeSchema(capability.input_schema),
2190
+ output_schema: capability.output_schema,
2191
+ permission: capability.permission,
2192
+ capability_id: capability.capability_id,
2193
+ trigger: capability.trigger
2194
+ };
2195
+ });
2196
+ }
2197
+ ensureUniqueToolName(baseName, names) {
2198
+ if (!names.has(baseName)) {
2199
+ names.add(baseName);
2200
+ return baseName;
2201
+ }
2202
+ let index = 2;
2203
+ while (names.has(`${baseName}_${index}`)) {
2204
+ index += 1;
2205
+ }
2206
+ const uniqueName = `${baseName}_${index}`;
2207
+ names.add(uniqueName);
2208
+ return uniqueName;
2209
+ }
2210
+ };
2211
+
2212
+ // src/core/runtime/ExecutionStore.ts
2213
+ var ExecutionStore = class {
2214
+ constructor() {
2215
+ this.registries = /* @__PURE__ */ new Map();
2216
+ }
2217
+ registerTools(registryKey, tools) {
2218
+ const registry = /* @__PURE__ */ new Map();
2219
+ for (const tool of tools) {
2220
+ registry.set(tool.tool_name, tool);
2221
+ }
2222
+ this.registries.set(registryKey, registry);
2223
+ }
2224
+ hasRegistry(registryKey) {
2225
+ return this.registries.has(registryKey);
2226
+ }
2227
+ getTool(registryKey, toolName) {
2228
+ return this.registries.get(registryKey)?.get(toolName);
2229
+ }
2230
+ clear(registryKey) {
2231
+ if (registryKey) {
2232
+ this.registries.delete(registryKey);
2233
+ return;
2234
+ }
2235
+ this.registries.clear();
2236
+ }
2237
+ };
2238
+
2239
+ // src/core/runtime/LifecycleReporter.ts
2240
+ var LifecycleReporter = class {
2241
+ constructor() {
2242
+ this.handlers = /* @__PURE__ */ new Set();
2243
+ }
2244
+ onEvent(handler) {
2245
+ this.handlers.add(handler);
2246
+ return () => {
2247
+ this.handlers.delete(handler);
2248
+ };
2249
+ }
2250
+ emit(event) {
2251
+ for (const handler of this.handlers) {
2252
+ try {
2253
+ handler(event);
2254
+ } catch {
2255
+ }
2256
+ }
2257
+ }
2258
+ };
2259
+
2260
+ // src/core/runtime/RetryPolicy.ts
2261
+ function defaultShouldRetry(error) {
2262
+ if (error && typeof error === "object") {
2263
+ const status = error.statusCode;
2264
+ if (typeof status === "number") {
2265
+ return status >= 500 || status === 429;
2266
+ }
2267
+ }
2268
+ return true;
2269
+ }
2270
+ var RetryPolicy = class {
2271
+ constructor(options = {}) {
2272
+ this.maxAttempts = Math.max(1, options.maxAttempts ?? 3);
2273
+ this.baseDelayMs = Math.max(0, options.baseDelayMs ?? 150);
2274
+ this.maxDelayMs = Math.max(this.baseDelayMs, options.maxDelayMs ?? 2e3);
2275
+ this.shouldRetry = options.shouldRetry || ((error) => defaultShouldRetry(error));
2276
+ }
2277
+ async execute(operation) {
2278
+ let lastError = null;
2279
+ for (let attempt = 1; attempt <= this.maxAttempts; attempt += 1) {
2280
+ try {
2281
+ return await operation(attempt);
2282
+ } catch (error) {
2283
+ lastError = error;
2284
+ const canRetry = attempt < this.maxAttempts && this.shouldRetry(error, attempt);
2285
+ if (!canRetry) throw error;
2286
+ const delayMs = Math.min(this.maxDelayMs, this.baseDelayMs * 2 ** (attempt - 1));
2287
+ if (delayMs > 0) {
2288
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
2289
+ }
2290
+ }
2291
+ }
2292
+ throw lastError instanceof Error ? lastError : new Error("Retry operation failed");
2293
+ }
2294
+ };
2295
+
2296
+ // src/core/runtime/ContractRuntime.ts
2297
+ var LIFECYCLE_EVENTS = /* @__PURE__ */ new Set([
2298
+ "task.claimed",
2299
+ "task.started",
2300
+ "task.progress",
2301
+ "task.completed",
2302
+ "task.failed",
2303
+ "task.canceled"
2304
+ ]);
2305
+ var DEFAULT_PROVIDER = "gemini";
2306
+ function isRecord3(value) {
2307
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2308
+ }
2309
+ function toRecord(value) {
2310
+ return isRecord3(value) ? value : {};
2311
+ }
2312
+ function resolveToolCallId(input) {
2313
+ if (typeof input.tool_call_id === "string" && input.tool_call_id.trim().length > 0) {
2314
+ return input.tool_call_id;
2315
+ }
2316
+ const payload = isRecord3(input.payload) ? input.payload : void 0;
2317
+ if (payload && typeof payload.tool_call_id === "string" && payload.tool_call_id.trim().length > 0) {
2318
+ return payload.tool_call_id;
2319
+ }
2320
+ const data = isRecord3(input.data) ? input.data : void 0;
2321
+ if (data && typeof data.tool_call_id === "string" && data.tool_call_id.trim().length > 0) {
2322
+ return data.tool_call_id;
2323
+ }
2324
+ return void 0;
2325
+ }
2326
+ var ContractRuntime = class {
2327
+ constructor(options) {
2328
+ if (!options.baseUrl) {
2329
+ throw new ContractValidationError("ContractRuntime requires baseUrl");
2330
+ }
2331
+ this.appId = options.appId;
2332
+ this.appName = options.appName;
2333
+ this.defaultNamespace = options.namespace;
2334
+ this.httpClient = new ContractHttpClient({
2335
+ baseUrl: options.baseUrl,
2336
+ appId: options.appId,
2337
+ appName: options.appName,
2338
+ apiKey: options.apiKey,
2339
+ fetchImpl: options.fetchImpl
2340
+ });
2341
+ this.contractClient = new ContractClient(this.httpClient, {
2342
+ cache: new ContractCache(options.cacheTtlMs ?? 3e4)
2343
+ });
2344
+ this.toolProjector = new ToolProjector();
2345
+ this.executionStore = new ExecutionStore();
2346
+ this.lifecycleReporter = new LifecycleReporter();
2347
+ this.scopeGuard = new ScopeGuard(options.permissions || []);
2348
+ this.retryPolicy = new RetryPolicy(options.retry);
2349
+ }
2350
+ async getContract(appId) {
2351
+ this.assertAppContext(appId);
2352
+ return this.contractClient.getLocalAppV1(false);
2353
+ }
2354
+ async getTools(input) {
2355
+ this.assertAppContext(input.appId);
2356
+ const contract = await this.contractClient.getLocalAppV1(false);
2357
+ const tools = this.toolProjector.project({
2358
+ contract,
2359
+ provider: input.provider,
2360
+ appId: input.appId,
2361
+ namespace: input.namespace || this.defaultNamespace || input.appId
2362
+ });
2363
+ this.executionStore.registerTools(
2364
+ this.buildRegistryKey(input.appId, input.provider, input.namespace),
2365
+ tools
2366
+ );
2367
+ return tools;
2368
+ }
2369
+ async executeToolCall(call, context) {
2370
+ try {
2371
+ this.assertAppContext(context.appId);
2372
+ const provider = context.provider || DEFAULT_PROVIDER;
2373
+ const namespace = context.namespace || this.defaultNamespace || context.appId;
2374
+ const registryKey = this.buildRegistryKey(context.appId, provider, namespace);
2375
+ if (!this.executionStore.hasRegistry(registryKey)) {
2376
+ await this.getTools({
2377
+ appId: context.appId,
2378
+ provider,
2379
+ namespace
2380
+ });
2381
+ }
2382
+ const tool = this.executionStore.getTool(registryKey, call.tool_name);
2383
+ if (!tool) {
2384
+ throw new ToolNotFoundError(call.tool_name, {
2385
+ registryKey
2386
+ });
2387
+ }
2388
+ this.scopeGuard.assert(tool.permission);
2389
+ const validationErrors = this.validateToolArgs(tool, call.args);
2390
+ if (validationErrors.length > 0) {
2391
+ throw new ToolValidationError("Tool input validation failed", {
2392
+ tool_name: call.tool_name,
2393
+ errors: validationErrors
2394
+ });
2395
+ }
2396
+ const eventId = context.idempotencyKey || call.tool_call_id;
2397
+ const requestBody = this.buildTriggerRequestBody(call, context, tool, eventId);
2398
+ const response = await this.retryPolicy.execute(
2399
+ () => this.httpClient.post(tool.trigger.route || "/webhooks/realtimex", requestBody)
2400
+ );
2401
+ if (response.success === false) {
2402
+ throw new RuntimeTransportError(response.error || "Failed to trigger task", void 0, response);
2403
+ }
2404
+ const taskId = this.resolveTaskId(response);
2405
+ const attemptId = normalizeAttemptId(response.attempt_id);
2406
+ this.tryEmitLifecycleEvent({
2407
+ tool_call_id: call.tool_call_id,
2408
+ task_id: taskId,
2409
+ attempt_id: attemptId,
2410
+ event_type: response.event_type,
2411
+ event_id: response.event_id,
2412
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2413
+ payload: toRecord(response)
2414
+ });
2415
+ if (taskId) {
2416
+ return {
2417
+ status: "queued",
2418
+ tool_call_id: call.tool_call_id,
2419
+ task_id: taskId,
2420
+ attempt_id: attemptId,
2421
+ output: {
2422
+ message: response.message || "Task accepted"
2423
+ }
2424
+ };
2425
+ }
2426
+ return {
2427
+ status: "completed",
2428
+ tool_call_id: call.tool_call_id,
2429
+ output: toRecord(response)
2430
+ };
2431
+ } catch (error) {
2432
+ return this.toFailedResult(call.tool_call_id, error);
2433
+ }
2434
+ }
2435
+ onExecutionEvent(handler) {
2436
+ return this.lifecycleReporter.onEvent(handler);
2437
+ }
2438
+ ingestExecutionEvent(input) {
2439
+ const eventTypeRaw = typeof input.event_type === "string" && input.event_type || typeof input.event === "string" && input.event || "";
2440
+ const normalized = normalizeContractEvent(eventTypeRaw);
2441
+ if (!normalized || !LIFECYCLE_EVENTS.has(normalized)) {
2442
+ return null;
2443
+ }
2444
+ const taskId = typeof input.task_id === "string" && input.task_id || typeof input.task_uuid === "string" && input.task_uuid || "";
2445
+ if (!taskId) return null;
2446
+ const event = {
2447
+ tool_call_id: resolveToolCallId(input) || taskId,
2448
+ task_id: taskId,
2449
+ attempt_id: normalizeAttemptId(input.attempt_id),
2450
+ event_type: normalized,
2451
+ event_id: typeof input.event_id === "string" && input.event_id || `${taskId}:${normalized}:${Date.now()}`,
2452
+ timestamp: typeof input.timestamp === "string" && input.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
2453
+ payload: toRecord(input.payload || input.data)
2454
+ };
2455
+ this.lifecycleReporter.emit(event);
2456
+ return event;
2457
+ }
2458
+ clearCache() {
2459
+ this.contractClient.clearCache();
2460
+ this.executionStore.clear();
2461
+ }
2462
+ assertAppContext(appId) {
2463
+ if (!appId || appId.trim().length === 0) {
2464
+ throw new ContractValidationError("appId is required");
2465
+ }
2466
+ if (this.appId && this.appId !== appId) {
2467
+ throw new ContractValidationError("Runtime appId mismatch", {
2468
+ runtime_app_id: this.appId,
2469
+ requested_app_id: appId
2470
+ });
2471
+ }
2472
+ }
2473
+ buildRegistryKey(appId, provider, namespace) {
2474
+ const resolvedNamespace = namespace || this.defaultNamespace || appId;
2475
+ return `${appId}:${provider}:${resolvedNamespace}`;
2476
+ }
2477
+ resolveTaskId(response) {
2478
+ if (typeof response.task_uuid === "string" && response.task_uuid.trim().length > 0) {
2479
+ return response.task_uuid;
2480
+ }
2481
+ if (typeof response.task_id === "string" && response.task_id.trim().length > 0) {
2482
+ return response.task_id;
2483
+ }
2484
+ return void 0;
2485
+ }
2486
+ buildTriggerRequestBody(call, context, tool, eventId) {
2487
+ const payloadTemplate = isRecord3(tool.trigger.payload_template) ? tool.trigger.payload_template : {};
2488
+ const templateRawData = isRecord3(payloadTemplate.raw_data) ? payloadTemplate.raw_data : {};
2489
+ const payload = {
2490
+ ...payloadTemplate,
2491
+ raw_data: {
2492
+ ...templateRawData,
2493
+ capability_id: tool.capability_id,
2494
+ tool_name: call.tool_name,
2495
+ tool_call_id: call.tool_call_id,
2496
+ args: call.args,
2497
+ context: {
2498
+ user_id: context.userId,
2499
+ workspace_id: context.workspaceId || null,
2500
+ request_id: context.requestId || null,
2501
+ metadata: context.metadata || null
2502
+ }
2503
+ }
2504
+ };
2505
+ if (typeof payload.auto_run !== "boolean") {
2506
+ payload.auto_run = false;
2507
+ }
2508
+ return {
2509
+ app_name: this.appName,
2510
+ app_id: this.appId || context.appId,
2511
+ event: tool.trigger.event,
2512
+ event_id: eventId,
2513
+ payload
2514
+ };
2515
+ }
2516
+ validateToolArgs(tool, args) {
2517
+ const errors = [];
2518
+ if (!isRecord3(args)) {
2519
+ errors.push("args must be an object");
2520
+ return errors;
2521
+ }
2522
+ const requiredFields = Array.isArray(tool.input_schema.required) ? tool.input_schema.required.filter((field) => typeof field === "string") : [];
2523
+ for (const field of requiredFields) {
2524
+ const value = args[field];
2525
+ if (value === void 0 || value === null || typeof value === "string" && value.trim().length === 0) {
2526
+ errors.push(`Missing required field: ${field}`);
2527
+ }
2528
+ }
2529
+ const properties = isRecord3(tool.input_schema.properties) ? tool.input_schema.properties : {};
2530
+ for (const [field, schemaValue] of Object.entries(properties)) {
2531
+ if (!(field in args)) continue;
2532
+ if (!isRecord3(schemaValue)) continue;
2533
+ const typeValue = schemaValue.type;
2534
+ if (typeof typeValue === "string") {
2535
+ if (!this.matchesType(args[field], typeValue)) {
2536
+ errors.push(`Invalid type for ${field}: expected ${typeValue}`);
2537
+ }
2538
+ }
2539
+ if (Array.isArray(typeValue)) {
2540
+ const valid = typeValue.some(
2541
+ (item) => typeof item === "string" && this.matchesType(args[field], item)
2542
+ );
2543
+ if (!valid) {
2544
+ errors.push(
2545
+ `Invalid type for ${field}: expected one of ${typeValue.filter((item) => typeof item === "string").join(", ")}`
2546
+ );
2547
+ }
2548
+ }
2549
+ }
2550
+ return errors;
2551
+ }
2552
+ matchesType(value, expectedType) {
2553
+ switch (expectedType) {
2554
+ case "string":
2555
+ return typeof value === "string";
2556
+ case "number":
2557
+ return typeof value === "number" && Number.isFinite(value);
2558
+ case "integer":
2559
+ return typeof value === "number" && Number.isInteger(value);
2560
+ case "boolean":
2561
+ return typeof value === "boolean";
2562
+ case "object":
2563
+ return isRecord3(value);
2564
+ case "array":
2565
+ return Array.isArray(value);
2566
+ case "null":
2567
+ return value === null;
2568
+ default:
2569
+ return true;
2570
+ }
2571
+ }
2572
+ tryEmitLifecycleEvent(input) {
2573
+ if (!input.task_id || !input.event_type) return;
2574
+ const normalized = normalizeContractEvent(input.event_type);
2575
+ if (!normalized || !LIFECYCLE_EVENTS.has(normalized)) {
2576
+ return;
2577
+ }
2578
+ this.lifecycleReporter.emit({
2579
+ tool_call_id: input.tool_call_id,
2580
+ task_id: input.task_id,
2581
+ attempt_id: normalizeAttemptId(input.attempt_id),
2582
+ event_type: normalized,
2583
+ event_id: input.event_id || `${input.task_id}:${normalized}:${Date.now()}`,
2584
+ timestamp: input.timestamp,
2585
+ payload: input.payload
2586
+ });
2587
+ }
2588
+ toFailedResult(toolCallId, error) {
2589
+ if (error instanceof ContractError) {
2590
+ const retryable = error instanceof RuntimeTransportError ? error.statusCode === void 0 || error.statusCode >= 500 || error.statusCode === 429 : false;
2591
+ return {
2592
+ status: "failed",
2593
+ tool_call_id: toolCallId,
2594
+ error: {
2595
+ code: error.code,
2596
+ message: error.message,
2597
+ retryable
2598
+ }
2599
+ };
2600
+ }
2601
+ if (error instanceof Error) {
2602
+ return {
2603
+ status: "failed",
2604
+ tool_call_id: toolCallId,
2605
+ error: {
2606
+ code: "runtime_error",
2607
+ message: error.message,
2608
+ retryable: true
2609
+ }
2610
+ };
2611
+ }
2612
+ return {
2613
+ status: "failed",
2614
+ tool_call_id: toolCallId,
2615
+ error: {
2616
+ code: "runtime_error",
2617
+ message: "Unknown runtime error",
2618
+ retryable: true
2619
+ }
2620
+ };
2621
+ }
2622
+ };
2623
+
2624
+ // src/core/auth/AuthProvider.ts
2625
+ var StaticAuthProvider = class {
2626
+ constructor(options = {}) {
2627
+ this.appId = options.appId;
2628
+ this.appName = options.appName;
2629
+ this.apiKey = options.apiKey;
2630
+ }
2631
+ buildHeaders(baseHeaders = {}) {
2632
+ const headers = { ...baseHeaders };
2633
+ if (this.apiKey) {
2634
+ headers.Authorization = `Bearer ${this.apiKey}`;
2635
+ }
2636
+ if (this.appId) {
2637
+ headers["x-app-id"] = this.appId;
2638
+ }
2639
+ if (this.appName) {
2640
+ headers["x-app-name"] = this.appName;
2641
+ }
2642
+ return headers;
2643
+ }
2644
+ };
2645
+
2646
+ // src/adapters/gemini/GeminiToolAdapter.ts
2647
+ function isRecord4(value) {
2648
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2649
+ }
2650
+ function parseArgs(value) {
2651
+ if (isRecord4(value)) return value;
2652
+ if (typeof value === "string") {
2653
+ try {
2654
+ const parsed = JSON.parse(value);
2655
+ return isRecord4(parsed) ? parsed : {};
2656
+ } catch {
2657
+ return {};
2658
+ }
2659
+ }
2660
+ return {};
2661
+ }
2662
+ var GeminiToolAdapter = class {
2663
+ toProviderTools(tools) {
2664
+ return tools.map((tool) => ({
2665
+ name: tool.tool_name,
2666
+ description: tool.description,
2667
+ parameters: tool.input_schema
2668
+ }));
2669
+ }
2670
+ fromProviderToolCall(call) {
2671
+ return {
2672
+ tool_call_id: call.id,
2673
+ tool_name: call.name,
2674
+ args: parseArgs(call.args)
2675
+ };
2676
+ }
2677
+ toProviderResult(result) {
2678
+ return {
2679
+ tool_call_id: result.tool_call_id || result.task_id || "unknown",
2680
+ status: result.status,
2681
+ payload: result.status === "failed" ? { error: result.error } : {
2682
+ ...result.output || {},
2683
+ task_id: result.task_id,
2684
+ attempt_id: result.attempt_id
2685
+ }
2686
+ };
2687
+ }
2688
+ };
2689
+
2690
+ // src/adapters/claude/ClaudeToolAdapter.ts
2691
+ var ClaudeToolAdapter = class {
2692
+ toProviderTools(tools) {
2693
+ return tools.map((tool) => ({
2694
+ name: tool.tool_name,
2695
+ description: tool.description,
2696
+ input_schema: tool.input_schema
2697
+ }));
2698
+ }
2699
+ fromProviderToolCall(call) {
2700
+ return {
2701
+ tool_call_id: call.id,
2702
+ tool_name: call.name,
2703
+ args: call.input || {}
2704
+ };
2705
+ }
2706
+ toProviderResult(result) {
2707
+ const contentPayload = result.status === "failed" ? { error: result.error } : {
2708
+ ...result.output || {},
2709
+ task_id: result.task_id,
2710
+ attempt_id: result.attempt_id
2711
+ };
2712
+ return {
2713
+ type: "tool_result",
2714
+ tool_use_id: result.tool_call_id || result.task_id || "unknown",
2715
+ content: JSON.stringify(contentPayload),
2716
+ is_error: result.status === "failed" ? true : void 0
2717
+ };
2718
+ }
2719
+ };
2720
+
2721
+ // src/adapters/codex/CodexToolAdapter.ts
2722
+ function isRecord5(value) {
2723
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2724
+ }
2725
+ function parseArguments(value) {
2726
+ if (isRecord5(value)) return value;
2727
+ if (typeof value === "string") {
2728
+ try {
2729
+ const parsed = JSON.parse(value);
2730
+ return isRecord5(parsed) ? parsed : {};
2731
+ } catch {
2732
+ return {};
2733
+ }
2734
+ }
2735
+ return {};
2736
+ }
2737
+ var CodexToolAdapter = class {
2738
+ toProviderTools(tools) {
2739
+ return tools.map((tool) => ({
2740
+ type: "function",
2741
+ function: {
2742
+ name: tool.tool_name,
2743
+ description: tool.description,
2744
+ parameters: tool.input_schema
2745
+ }
2746
+ }));
2747
+ }
2748
+ fromProviderToolCall(call) {
2749
+ return {
2750
+ tool_call_id: call.id,
2751
+ tool_name: call.function.name,
2752
+ args: parseArguments(call.function.arguments)
2753
+ };
2754
+ }
2755
+ toProviderResult(result) {
2756
+ const outputPayload = result.status === "failed" ? { error: result.error } : {
2757
+ ...result.output || {},
2758
+ task_id: result.task_id,
2759
+ attempt_id: result.attempt_id
2760
+ };
2761
+ return {
2762
+ tool_call_id: result.tool_call_id || result.task_id || "unknown",
2763
+ output: JSON.stringify(outputPayload),
2764
+ is_error: result.status === "failed" ? true : void 0
2765
+ };
2766
+ }
2767
+ };
2768
+
2769
+ // src/acp/ACPEventMapper.ts
2770
+ function getErrorMessage(error) {
2771
+ if (error instanceof Error) return error.message;
2772
+ if (typeof error === "string") return error;
2773
+ return "Unknown error";
2774
+ }
2775
+ function buildRealtimeXMeta(input) {
2776
+ return {
2777
+ realtimex: {
2778
+ tool_call_id: input.reference.toolCallId,
2779
+ task_id: input.taskId,
2780
+ attempt_id: input.attemptId,
2781
+ event_id: input.eventId,
2782
+ contract_version: "local-app-contract/v1",
2783
+ contract_event: input.contractEvent,
2784
+ cancelled: input.cancelled === true ? true : void 0,
2785
+ app_id: input.reference.appId,
2786
+ user_id: input.reference.userId,
2787
+ workspace_id: input.reference.workspaceId,
2788
+ provider: input.reference.provider,
2789
+ namespace: input.reference.namespace
2790
+ }
2791
+ };
2792
+ }
2793
+ var ACPEventMapper = class {
2794
+ createReference(invocation, context) {
2795
+ return {
2796
+ sessionId: context.sessionId,
2797
+ toolCallId: invocation.toolCallId,
2798
+ appId: context.appId,
2799
+ userId: context.userId,
2800
+ workspaceId: context.workspaceId,
2801
+ provider: context.provider,
2802
+ namespace: context.namespace,
2803
+ title: invocation.title || invocation.toolName,
2804
+ kind: invocation.kind || "execute"
2805
+ };
2806
+ }
2807
+ buildPendingUpdate(invocation, reference) {
2808
+ return {
2809
+ sessionId: reference.sessionId,
2810
+ update: {
2811
+ type: "tool_call",
2812
+ toolCallId: invocation.toolCallId,
2813
+ title: reference.title,
2814
+ kind: reference.kind,
2815
+ status: "pending",
2816
+ rawInput: invocation.args,
2817
+ _meta: buildRealtimeXMeta({
2818
+ reference,
2819
+ contractEvent: "task.trigger"
2820
+ })
2821
+ }
2822
+ };
2823
+ }
2824
+ buildResultUpdate(result, reference) {
2825
+ const status = this.mapExecutionResultStatus(result);
2826
+ const taskId = result.task_id;
2827
+ const attemptId = result.attempt_id;
2828
+ const contractEvent = status === "completed" ? "task.completed" : status === "failed" ? "task.failed" : "task.started";
2829
+ const rawOutput = status === "failed" ? {
2830
+ error: result.error || {
2831
+ code: "runtime_error",
2832
+ message: "Unknown runtime error",
2833
+ retryable: true
2834
+ }
2835
+ } : {
2836
+ ...result.output || {},
2837
+ task_id: taskId,
2838
+ attempt_id: attemptId
2839
+ };
2840
+ return {
2841
+ sessionId: reference.sessionId,
2842
+ update: {
2843
+ type: "tool_call_update",
2844
+ toolCallId: reference.toolCallId,
2845
+ status,
2846
+ content: [
2847
+ {
2848
+ type: "text",
2849
+ text: status === "in_progress" ? "Task queued" : status === "completed" ? "Task completed" : "Task failed"
2850
+ }
2851
+ ],
2852
+ rawOutput,
2853
+ _meta: buildRealtimeXMeta({
2854
+ reference,
2855
+ taskId,
2856
+ attemptId,
2857
+ contractEvent
2858
+ })
2859
+ }
2860
+ };
2861
+ }
2862
+ buildLifecycleUpdate(event, reference) {
2863
+ const status = this.mapContractEventStatus(event.event_type);
2864
+ if (!status) return null;
2865
+ const payload = event.payload || {};
2866
+ const progressText = this.resolveEventText(event.event_type, payload);
2867
+ const cancelled = event.event_type === "task.canceled";
2868
+ return {
2869
+ sessionId: reference.sessionId,
2870
+ update: {
2871
+ type: "tool_call_update",
2872
+ toolCallId: reference.toolCallId,
2873
+ status,
2874
+ content: progressText ? [
2875
+ {
2876
+ type: "text",
2877
+ text: progressText
2878
+ }
2879
+ ] : void 0,
2880
+ rawOutput: payload,
2881
+ _meta: buildRealtimeXMeta({
2882
+ reference,
2883
+ taskId: event.task_id,
2884
+ attemptId: event.attempt_id,
2885
+ eventId: event.event_id,
2886
+ contractEvent: event.event_type,
2887
+ cancelled
2888
+ })
2889
+ }
2890
+ };
2891
+ }
2892
+ buildNotifyFailureUpdate(reference, error) {
2893
+ return {
2894
+ sessionId: reference.sessionId,
2895
+ update: {
2896
+ type: "tool_call_update",
2897
+ toolCallId: reference.toolCallId,
2898
+ status: "failed",
2899
+ content: [
2900
+ {
2901
+ type: "text",
2902
+ text: `Adapter notify failed: ${getErrorMessage(error)}`
2903
+ }
2904
+ ],
2905
+ rawOutput: {
2906
+ error: {
2907
+ code: "acp_notify_failed",
2908
+ message: getErrorMessage(error)
2909
+ }
2910
+ },
2911
+ _meta: buildRealtimeXMeta({
2912
+ reference,
2913
+ contractEvent: "adapter.notify_failed"
2914
+ })
2915
+ }
2916
+ };
2917
+ }
2918
+ mapContractEventStatus(eventType) {
2919
+ switch (eventType) {
2920
+ case "task.claimed":
2921
+ case "task.started":
2922
+ case "task.progress":
2923
+ return "in_progress";
2924
+ case "task.completed":
2925
+ return "completed";
2926
+ case "task.failed":
2927
+ case "task.canceled":
2928
+ return "failed";
2929
+ default:
2930
+ return null;
2931
+ }
2932
+ }
2933
+ mapExecutionResultStatus(result) {
2934
+ switch (result.status) {
2935
+ case "completed":
2936
+ return "completed";
2937
+ case "failed":
2938
+ return "failed";
2939
+ case "queued":
2940
+ return "in_progress";
2941
+ default:
2942
+ return "failed";
2943
+ }
2944
+ }
2945
+ resolveEventText(eventType, payload) {
2946
+ const payloadMessage = typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error : void 0;
2947
+ if (payloadMessage) return payloadMessage;
2948
+ switch (eventType) {
2949
+ case "task.claimed":
2950
+ return "Task claimed";
2951
+ case "task.started":
2952
+ return "Task started";
2953
+ case "task.progress":
2954
+ return "Task in progress";
2955
+ case "task.completed":
2956
+ return "Task completed";
2957
+ case "task.failed":
2958
+ return "Task failed";
2959
+ case "task.canceled":
2960
+ return "Task canceled";
2961
+ default:
2962
+ return void 0;
2963
+ }
2964
+ }
2965
+ };
2966
+
2967
+ // src/acp/ACPPermissionBridge.ts
2968
+ function isRecord6(value) {
2969
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2970
+ }
2971
+ function normalizePermissionOptions(invocation, buildPermissionOptions) {
2972
+ const built = buildPermissionOptions ? buildPermissionOptions(invocation) : void 0;
2973
+ if (built && built.length > 0) return built;
2974
+ return [
2975
+ {
2976
+ id: "allow_once",
2977
+ label: "Allow once",
2978
+ kind: "allow_once"
2979
+ },
2980
+ {
2981
+ id: "deny_once",
2982
+ label: "Deny",
2983
+ kind: "deny_once"
2984
+ }
2985
+ ];
2986
+ }
2987
+ function parseDecision(response) {
2988
+ if (typeof response === "boolean") return response;
2989
+ if (!isRecord6(response)) return false;
2990
+ if (typeof response.allow === "boolean") return response.allow;
2991
+ const decision = typeof response.decision === "string" && response.decision || typeof response.outcome === "string" && response.outcome || typeof response.selected === "string" && response.selected || "";
2992
+ const normalized = decision.trim().toLowerCase();
2993
+ if (!normalized) return false;
2994
+ return normalized === "allow" || normalized === "allow_once" || normalized === "allow_always" || normalized === "approved" || normalized === "granted";
2995
+ }
2996
+ var ACPPermissionBridge = class {
2997
+ constructor(options) {
2998
+ this.notifier = options.notifier;
2999
+ this.enabled = options.enabled;
3000
+ this.buildPermissionOptions = options.buildPermissionOptions;
3001
+ }
3002
+ async requestToolPermission(invocation, context) {
3003
+ if (!this.enabled) return true;
3004
+ if (!this.notifier.request) {
3005
+ return false;
3006
+ }
3007
+ const options = normalizePermissionOptions(invocation, this.buildPermissionOptions);
3008
+ try {
3009
+ const response = await this.notifier.request("session/request_permission", {
3010
+ sessionId: context.sessionId,
3011
+ title: invocation.title || invocation.toolName,
3012
+ description: `Allow tool ${invocation.toolName} to run?`,
3013
+ options,
3014
+ metadata: {
3015
+ tool_call_id: invocation.toolCallId,
3016
+ tool_name: invocation.toolName,
3017
+ app_id: context.appId
3018
+ }
3019
+ });
3020
+ return parseDecision(response);
3021
+ } catch {
3022
+ return false;
3023
+ }
3024
+ }
3025
+ };
3026
+
3027
+ // src/acp/ACPTelemetry.ts
3028
+ var ACPTelemetry = class {
3029
+ constructor(sink) {
3030
+ this.sink = sink;
3031
+ }
3032
+ emit(event) {
3033
+ if (!this.sink) return;
3034
+ try {
3035
+ const output = this.sink.emit(event);
3036
+ if (output && typeof output.then === "function") {
3037
+ void output.catch(() => {
3038
+ });
3039
+ }
3040
+ } catch {
3041
+ }
3042
+ }
3043
+ };
3044
+
3045
+ // src/acp/ACPContractAdapter.ts
3046
+ function isRecord7(value) {
3047
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3048
+ }
3049
+ function getString(value) {
3050
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
3051
+ }
3052
+ function resolveTaskId(payload) {
3053
+ return getString(payload.task_id) || getString(payload.task_uuid);
3054
+ }
3055
+ function resolveToolCallId2(payload) {
3056
+ const direct = getString(payload.tool_call_id);
3057
+ if (direct) return direct;
3058
+ if (isRecord7(payload.payload)) {
3059
+ const nestedPayload = getString(payload.payload.tool_call_id);
3060
+ if (nestedPayload) return nestedPayload;
3061
+ }
3062
+ if (isRecord7(payload.data)) {
3063
+ const nestedData = getString(payload.data.tool_call_id);
3064
+ if (nestedData) return nestedData;
3065
+ }
3066
+ return void 0;
3067
+ }
3068
+ function isTerminalStatus(status) {
3069
+ return status === "completed" || status === "failed";
3070
+ }
3071
+ var ACPContractAdapter = class {
3072
+ constructor(options) {
3073
+ this.taskReferences = /* @__PURE__ */ new Map();
3074
+ this.toolCallReferences = /* @__PURE__ */ new Map();
3075
+ this.runtime = options.runtime;
3076
+ this.notifier = options.notifier;
3077
+ this.mapper = new ACPEventMapper();
3078
+ this.permissionBridge = new ACPPermissionBridge({
3079
+ notifier: options.notifier,
3080
+ enabled: options.requestPermission === true,
3081
+ buildPermissionOptions: options.buildPermissionOptions
3082
+ });
3083
+ this.telemetry = new ACPTelemetry(options.telemetry);
3084
+ this.runtimeUnsubscribe = this.runtime.onExecutionEvent((event) => {
3085
+ void this.handleRuntimeEvent(event);
3086
+ });
3087
+ }
3088
+ dispose() {
3089
+ this.runtimeUnsubscribe();
3090
+ this.taskReferences.clear();
3091
+ this.toolCallReferences.clear();
3092
+ }
3093
+ async executeTool(invocation, context) {
3094
+ const reference = this.mapper.createReference(invocation, context);
3095
+ this.rememberReference(reference);
3096
+ await this.notify(this.mapper.buildPendingUpdate(invocation, reference));
3097
+ const permissionGranted = await this.permissionBridge.requestToolPermission(
3098
+ invocation,
3099
+ context
3100
+ );
3101
+ this.telemetry.emit({
3102
+ phase: "permission",
3103
+ result: permissionGranted ? "ok" : "failed",
3104
+ sessionId: context.sessionId,
3105
+ toolCallId: invocation.toolCallId,
3106
+ toolName: invocation.toolName
3107
+ });
3108
+ if (!permissionGranted) {
3109
+ const result2 = {
3110
+ status: "failed",
3111
+ tool_call_id: invocation.toolCallId,
3112
+ error: {
3113
+ code: "permission_denied",
3114
+ message: `Permission denied for ${invocation.toolName}`,
3115
+ retryable: false
3116
+ }
3117
+ };
3118
+ await this.notify(this.mapper.buildResultUpdate(result2, reference));
3119
+ this.cleanupReference(reference, result2);
3120
+ return result2;
3121
+ }
3122
+ const result = await this.runtime.executeToolCall(
3123
+ {
3124
+ tool_call_id: invocation.toolCallId,
3125
+ tool_name: invocation.toolName,
3126
+ args: invocation.args
3127
+ },
3128
+ {
3129
+ appId: context.appId,
3130
+ userId: context.userId,
3131
+ workspaceId: context.workspaceId,
3132
+ provider: context.provider,
3133
+ namespace: context.namespace
3134
+ }
3135
+ );
3136
+ const normalizedResult = {
3137
+ ...result,
3138
+ tool_call_id: result.tool_call_id || invocation.toolCallId
3139
+ };
3140
+ if (normalizedResult.task_id) {
3141
+ this.taskReferences.set(normalizedResult.task_id, reference);
3142
+ }
3143
+ await this.notify(this.mapper.buildResultUpdate(normalizedResult, reference));
3144
+ this.telemetry.emit({
3145
+ phase: "execute",
3146
+ result: normalizedResult.status === "failed" ? "failed" : "ok",
3147
+ sessionId: reference.sessionId,
3148
+ toolCallId: reference.toolCallId,
3149
+ toolName: invocation.toolName,
3150
+ taskId: normalizedResult.task_id,
3151
+ attemptId: normalizedResult.attempt_id,
3152
+ status: normalizedResult.status === "queued" ? "in_progress" : normalizedResult.status === "completed" ? "completed" : normalizedResult.status === "failed" ? "failed" : void 0,
3153
+ error: normalizedResult.error?.message
3154
+ });
3155
+ this.cleanupReference(reference, normalizedResult);
3156
+ return normalizedResult;
3157
+ }
3158
+ ingestContractCallback(payload, context) {
3159
+ const initialTaskId = resolveTaskId(payload);
3160
+ const initialToolCallId = resolveToolCallId2(payload);
3161
+ if (initialTaskId) {
3162
+ const existingByTask = this.taskReferences.get(initialTaskId);
3163
+ const existingByCall = initialToolCallId ? this.toolCallReferences.get(initialToolCallId) : void 0;
3164
+ const reference = existingByTask || existingByCall || {
3165
+ sessionId: context.sessionId,
3166
+ toolCallId: initialToolCallId || initialTaskId,
3167
+ appId: "unknown",
3168
+ userId: "unknown",
3169
+ title: initialToolCallId || initialTaskId,
3170
+ kind: "other"
3171
+ };
3172
+ this.taskReferences.set(initialTaskId, reference);
3173
+ this.toolCallReferences.set(reference.toolCallId, reference);
3174
+ }
3175
+ const event = this.runtime.ingestExecutionEvent(payload);
3176
+ this.telemetry.emit({
3177
+ phase: "ingest",
3178
+ result: event ? "ok" : "skipped",
3179
+ sessionId: context.sessionId,
3180
+ toolCallId: event?.tool_call_id,
3181
+ taskId: event?.task_id,
3182
+ attemptId: event?.attempt_id,
3183
+ eventId: event?.event_id,
3184
+ eventType: event?.event_type
3185
+ });
3186
+ return event;
3187
+ }
3188
+ async handleRuntimeEvent(event) {
3189
+ const reference = this.resolveReferenceForEvent(event);
3190
+ if (!reference) {
3191
+ this.telemetry.emit({
3192
+ phase: "runtime_event",
3193
+ result: "skipped",
3194
+ toolCallId: event.tool_call_id,
3195
+ taskId: event.task_id,
3196
+ attemptId: event.attempt_id,
3197
+ eventId: event.event_id,
3198
+ eventType: event.event_type
3199
+ });
3200
+ return;
3201
+ }
3202
+ this.taskReferences.set(event.task_id, reference);
3203
+ const update = this.mapper.buildLifecycleUpdate(event, reference);
3204
+ if (!update) {
3205
+ this.telemetry.emit({
3206
+ phase: "runtime_event",
3207
+ result: "skipped",
3208
+ sessionId: reference.sessionId,
3209
+ toolCallId: reference.toolCallId,
3210
+ taskId: event.task_id,
3211
+ attemptId: event.attempt_id,
3212
+ eventId: event.event_id,
3213
+ eventType: event.event_type
3214
+ });
3215
+ return;
3216
+ }
3217
+ await this.notify(update);
3218
+ this.telemetry.emit({
3219
+ phase: "runtime_event",
3220
+ result: "ok",
3221
+ sessionId: reference.sessionId,
3222
+ toolCallId: reference.toolCallId,
3223
+ taskId: event.task_id,
3224
+ attemptId: event.attempt_id,
3225
+ eventId: event.event_id,
3226
+ eventType: event.event_type,
3227
+ status: update.update.status
3228
+ });
3229
+ if (isTerminalStatus(update.update.status)) {
3230
+ this.taskReferences.delete(event.task_id);
3231
+ this.toolCallReferences.delete(reference.toolCallId);
3232
+ }
3233
+ }
3234
+ resolveReferenceForEvent(event) {
3235
+ const byTask = this.taskReferences.get(event.task_id);
3236
+ if (byTask) return byTask;
3237
+ const byToolCall = this.toolCallReferences.get(event.tool_call_id);
3238
+ if (byToolCall) return byToolCall;
3239
+ return void 0;
3240
+ }
3241
+ rememberReference(reference) {
3242
+ this.toolCallReferences.set(reference.toolCallId, reference);
3243
+ }
3244
+ cleanupReference(reference, result) {
3245
+ const status = result.status === "queued" ? "in_progress" : result.status === "completed" ? "completed" : result.status === "failed" ? "failed" : "failed";
3246
+ if (!isTerminalStatus(status)) return;
3247
+ this.toolCallReferences.delete(reference.toolCallId);
3248
+ if (result.task_id) {
3249
+ this.taskReferences.delete(result.task_id);
3250
+ }
3251
+ }
3252
+ async notify(update) {
3253
+ try {
3254
+ await this.notifier.notify("session/update", update);
3255
+ this.telemetry.emit({
3256
+ phase: "notify",
3257
+ result: "ok",
3258
+ sessionId: update.sessionId,
3259
+ toolCallId: update.update.toolCallId,
3260
+ status: update.update.status,
3261
+ metadata: {
3262
+ type: update.update.type
3263
+ }
3264
+ });
3265
+ } catch (error) {
3266
+ const reference = this.toolCallReferences.get(update.update.toolCallId);
3267
+ this.telemetry.emit({
3268
+ phase: "notify",
3269
+ result: "failed",
3270
+ sessionId: update.sessionId,
3271
+ toolCallId: update.update.toolCallId,
3272
+ status: update.update.status,
3273
+ error: error instanceof Error ? error.message : "Unknown notify error"
3274
+ });
3275
+ if (!reference) return;
3276
+ const failureUpdate = this.mapper.buildNotifyFailureUpdate(reference, error);
3277
+ try {
3278
+ await this.notifier.notify("session/update", failureUpdate);
3279
+ } catch {
3280
+ }
3281
+ }
3282
+ }
3283
+ };
3284
+
1782
3285
  // src/index.ts
1783
3286
  var _RealtimeXSDK = class _RealtimeXSDK {
1784
3287
  constructor(config = {}) {
@@ -1805,6 +3308,13 @@ var _RealtimeXSDK = class _RealtimeXSDK {
1805
3308
  this.agent = new AgentModule(this.httpClient);
1806
3309
  this.mcp = new MCPModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
1807
3310
  this.contract = new ContractModule(this.realtimexUrl, this.appName, this.appId, this.apiKey);
3311
+ this.contractRuntime = new ContractRuntime({
3312
+ baseUrl: this.realtimexUrl,
3313
+ appId: this.appId || void 0,
3314
+ appName: this.appName,
3315
+ apiKey: this.apiKey,
3316
+ permissions: this.permissions
3317
+ });
1808
3318
  if (this.permissions.length > 0 && this.appId && !this.apiKey) {
1809
3319
  this.register().catch((err) => {
1810
3320
  console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
@@ -1906,6 +3416,10 @@ _RealtimeXSDK.DEFAULT_REALTIMEX_URL = "http://localhost:3001";
1906
3416
  var RealtimeXSDK = _RealtimeXSDK;
1907
3417
  // Annotate the CommonJS export names for ESM import in node:
1908
3418
  0 && (module.exports = {
3419
+ ACPContractAdapter,
3420
+ ACPEventMapper,
3421
+ ACPPermissionBridge,
3422
+ ACPTelemetry,
1909
3423
  ActivitiesModule,
1910
3424
  AgentModule,
1911
3425
  ApiModule,
@@ -1913,7 +3427,16 @@ var RealtimeXSDK = _RealtimeXSDK;
1913
3427
  CONTRACT_EVENT_ID_HEADER,
1914
3428
  CONTRACT_SIGNATURE_ALGORITHM,
1915
3429
  CONTRACT_SIGNATURE_HEADER,
3430
+ ClaudeToolAdapter,
3431
+ CodexToolAdapter,
3432
+ ContractCache,
3433
+ ContractClient,
3434
+ ContractError,
3435
+ ContractHttpClient,
1916
3436
  ContractModule,
3437
+ ContractRuntime,
3438
+ ContractValidationError,
3439
+ GeminiToolAdapter,
1917
3440
  LLMModule,
1918
3441
  LLMPermissionError,
1919
3442
  LLMProviderError,
@@ -1923,9 +3446,17 @@ var RealtimeXSDK = _RealtimeXSDK;
1923
3446
  PermissionRequiredError,
1924
3447
  PortModule,
1925
3448
  RealtimeXSDK,
3449
+ RetryPolicy,
3450
+ RuntimeTransportError,
1926
3451
  STTModule,
3452
+ ScopeDeniedError,
3453
+ ScopeGuard,
3454
+ StaticAuthProvider,
1927
3455
  TTSModule,
1928
3456
  TaskModule,
3457
+ ToolNotFoundError,
3458
+ ToolProjector,
3459
+ ToolValidationError,
1929
3460
  VectorStore,
1930
3461
  WebhookModule,
1931
3462
  buildContractIdempotencyKey,
@@ -1935,6 +3466,9 @@ var RealtimeXSDK = _RealtimeXSDK;
1935
3466
  hashContractPayload,
1936
3467
  normalizeAttemptId,
1937
3468
  normalizeContractEvent,
3469
+ normalizeLocalAppContractV1,
3470
+ normalizeSchema,
1938
3471
  parseAttemptRunId,
1939
- signContractEvent
3472
+ signContractEvent,
3473
+ toStableToolName
1940
3474
  });