@rayrun/sdk 0.4.0 → 0.5.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.
Files changed (4) hide show
  1. package/README.md +36 -0
  2. package/index.d.ts +130 -0
  3. package/index.js +18 -1
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -50,6 +50,42 @@ await rayrun.clients.setAccessProfile(clientUid, profile.uid, clientToolPolicyVe
50
50
  The effective policy is always the intersection of the workspace, profile, and client rules. A
51
51
  profile can narrow access but cannot grant something blocked by the workspace or client.
52
52
 
53
+ ## Manage hosted tool hooks
54
+
55
+ Hooks are versioned TypeScript adapters hosted and sandboxed by Rayrun. Pull the generated types and
56
+ draft, test it without a live upstream call, then create an immutable shadow or active revision.
57
+
58
+ ```js
59
+ const { hook } = await rayrun.hooks.get(connectionUid, toolUid);
60
+
61
+ const tested = await rayrun.hooks.test(connectionUid, toolUid, {
62
+ source: hook.draftSource,
63
+ config: hook.draftConfig,
64
+ arguments: { query: 'release' },
65
+ mockResult: { items: [] },
66
+ });
67
+
68
+ const saved = await rayrun.hooks.saveDraft(connectionUid, toolUid, {
69
+ source: hook.draftSource,
70
+ config: hook.draftConfig,
71
+ expectedVersion: hook.version,
72
+ });
73
+
74
+ await rayrun.hooks.deploy(connectionUid, toolUid, {
75
+ expectedVersion: saved.hook.version,
76
+ mode: 'shadow',
77
+ });
78
+
79
+ const runs = await rayrun.hooks.listRuns(connectionUid, toolUid, { limit: 25 });
80
+ ```
81
+
82
+ `setDeployment` moves an active or shadow pointer to an existing compatible revision, or deactivates
83
+ it with `revisionUid: null`. Every mutation uses `expectedVersion`; fetch and reconcile instead of
84
+ blindly retrying a `version_conflict`. Use a full-control API key for hook writes. Read-only keys can
85
+ inspect source, generated declarations, revision history, and deployed-run metadata; captured logs
86
+ and errors require `hooks:write`. `RayrunApiError.diagnostics` carries compiler line and column
87
+ details for editor and CI output.
88
+
53
89
  ## Stream code run-ahead
54
90
 
55
91
  A model harness that receives `execute_code` arguments incrementally can let Rayrun start eligible
package/index.d.ts CHANGED
@@ -51,6 +51,89 @@ export type Tool = {
51
51
  inputSchema: Record<string, unknown>;
52
52
  title: string | null;
53
53
  };
54
+ export type ToolHookPublicContract = {
55
+ description?: string;
56
+ inputSchema?: Record<string, unknown>;
57
+ outputSchema?: Record<string, unknown>;
58
+ };
59
+ export type ToolHookRevision = {
60
+ config: Record<string, JsonValue>;
61
+ createdAt: string;
62
+ publicContract: ToolHookPublicContract | null;
63
+ revisionNumber: number;
64
+ source: string;
65
+ sourceHash: string;
66
+ uid: string;
67
+ upstreamDefinitionHash: string;
68
+ };
69
+ export type ToolHook = {
70
+ activeRevisionStale: boolean;
71
+ activeRevisionUid: string | null;
72
+ draftConfig: Record<string, JsonValue>;
73
+ draftSource: string;
74
+ hookUid: string | null;
75
+ revisions: ToolHookRevision[];
76
+ shadowRevisionStale: boolean;
77
+ shadowRevisionUid: string | null;
78
+ target: {
79
+ definitionHash: string | null;
80
+ inputSchema: Record<string, unknown>;
81
+ name: string;
82
+ outputSchema: Record<string, unknown> | null;
83
+ toolUid: string;
84
+ };
85
+ types: string;
86
+ version: number;
87
+ };
88
+ export type ToolHookLogEntry = {
89
+ data?: JsonValue;
90
+ level: 'debug' | 'error' | 'info' | 'warn';
91
+ message: string;
92
+ };
93
+ export type ToolHookTestFailure = {
94
+ durationMs: number;
95
+ error: {
96
+ code: 'invalid_arguments' | 'invalid_outcome' | 'invalid_output' | 'runtime_error' | 'timeout';
97
+ message: string;
98
+ };
99
+ logs: ToolHookLogEntry[];
100
+ status: 'failed';
101
+ };
102
+ export type ToolHookBeforeTestResult =
103
+ | {
104
+ durationMs: number;
105
+ logs: ToolHookLogEntry[];
106
+ outcome:
107
+ | { action: 'continue'; arguments: JsonValue }
108
+ | { action: 'reject'; message: string; reason: string }
109
+ | { action: 'require_approval'; arguments: JsonValue; reason: string };
110
+ status: 'completed';
111
+ }
112
+ | ToolHookTestFailure;
113
+ export type ToolHookAfterTestResult =
114
+ | {
115
+ durationMs: number;
116
+ logs: ToolHookLogEntry[];
117
+ outcome:
118
+ | { action: 'return'; result: JsonValue }
119
+ | { action: 'fail'; message: string; reason: string };
120
+ status: 'completed';
121
+ }
122
+ | ToolHookTestFailure;
123
+ export type ToolHookRun = {
124
+ createdAt: string;
125
+ differsFromActive: boolean | null;
126
+ durationMs: number;
127
+ errorMessage: string | null;
128
+ id: string;
129
+ logs: ToolHookLogEntry[] | null;
130
+ outcome: 'approval-required' | 'continued' | 'failed' | 'rejected' | 'returned';
131
+ requestId: string;
132
+ revisionUid: string;
133
+ shadow: boolean;
134
+ stage: 'after' | 'before';
135
+ uid: string;
136
+ };
54
137
  export type Client = {
55
138
  accessProfile: Pick<AccessProfile, 'name' | 'uid'> | null;
56
139
  clientName: string;
@@ -243,6 +326,7 @@ export const CODE_RUN_AHEAD_META_KEY: 'io.rayrun/run-ahead-session';
243
326
 
244
327
  export class RayrunApiError extends Error {
245
328
  code: string;
329
+ diagnostics: Array<{ column?: number; line?: number; message: string }>;
246
330
  requestId: string | null;
247
331
  status: number;
248
332
  }
@@ -291,6 +375,52 @@ export class Rayrun {
291
375
  body: { decision: ToolDecision | null; riskConfirmed?: boolean; riskOverride?: Risk | null },
292
376
  ): Promise<void>;
293
377
  };
378
+ hooks: {
379
+ deploy(
380
+ connectionUid: string,
381
+ toolUid: string,
382
+ body: { expectedVersion: number; mode: 'active' | 'shadow' },
383
+ ): Promise<{ hook: ToolHook }>;
384
+ get(connectionUid: string, toolUid: string): Promise<{ hook: ToolHook }>;
385
+ listRuns(
386
+ connectionUid: string,
387
+ toolUid: string,
388
+ query?: PageQuery,
389
+ ): Promise<CursorPage<ToolHookRun>>;
390
+ saveDraft(
391
+ connectionUid: string,
392
+ toolUid: string,
393
+ body: {
394
+ config?: Record<string, JsonValue>;
395
+ expectedVersion: number;
396
+ source: string;
397
+ },
398
+ ): Promise<{ hook: ToolHook }>;
399
+ setDeployment(
400
+ connectionUid: string,
401
+ toolUid: string,
402
+ body: {
403
+ expectedVersion: number;
404
+ mode: 'active' | 'shadow';
405
+ revisionUid: string | null;
406
+ },
407
+ ): Promise<{ hook: ToolHook }>;
408
+ test(
409
+ connectionUid: string,
410
+ toolUid: string,
411
+ body: {
412
+ arguments: JsonValue;
413
+ config?: Record<string, JsonValue>;
414
+ mockResult?: JsonValue;
415
+ source: string;
416
+ },
417
+ ): Promise<{
418
+ after?: ToolHookAfterTestResult;
419
+ before: ToolHookBeforeTestResult;
420
+ publicContract: ToolHookPublicContract | null;
421
+ sourceHash: string;
422
+ }>;
423
+ };
294
424
  clients: {
295
425
  list(query?: PageQuery): Promise<CursorPage<Client>>;
296
426
  listTools(uid: string, query?: PageQuery & { query?: string }): Promise<CursorPage<ClientTool>>;
package/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { createHmac, timingSafeEqual } from 'node:crypto';
2
2
 
3
3
  export class RayrunApiError extends Error {
4
- constructor(message, { code, requestId, status }) {
4
+ constructor(message, { code, diagnostics = [], requestId, status }) {
5
5
  super(message);
6
6
  this.name = 'RayrunApiError';
7
7
  this.code = code;
8
+ this.diagnostics = diagnostics;
8
9
  this.requestId = requestId;
9
10
  this.status = status;
10
11
  }
@@ -112,6 +113,21 @@ export class Rayrun {
112
113
  setPolicy: (connectionUid, toolUid, body) =>
113
114
  this.request('PATCH', `/connections/${connectionUid}/tools/${toolUid}/policy`, { body }),
114
115
  };
116
+ const toolHookPath = (connectionUid, toolUid) =>
117
+ `/connections/${connectionUid}/tools/${toolUid}/hook`;
118
+ this.hooks = {
119
+ deploy: (connectionUid, toolUid, body) =>
120
+ this.request('POST', `${toolHookPath(connectionUid, toolUid)}/deploy`, { body }),
121
+ get: (connectionUid, toolUid) => this.request('GET', toolHookPath(connectionUid, toolUid)),
122
+ listRuns: (connectionUid, toolUid, query) =>
123
+ this.request('GET', `${toolHookPath(connectionUid, toolUid)}/runs`, { query }),
124
+ saveDraft: (connectionUid, toolUid, body) =>
125
+ this.request('PUT', toolHookPath(connectionUid, toolUid), { body }),
126
+ setDeployment: (connectionUid, toolUid, body) =>
127
+ this.request('POST', `${toolHookPath(connectionUid, toolUid)}/deployment`, { body }),
128
+ test: (connectionUid, toolUid, body) =>
129
+ this.request('POST', `${toolHookPath(connectionUid, toolUid)}/test`, { body }),
130
+ };
115
131
  this.clients = {
116
132
  list: (query) => this.request('GET', '/clients', { query }),
117
133
  listTools: (uid, query) => this.request('GET', `/clients/${uid}/tools`, { query }),
@@ -189,6 +205,7 @@ export class Rayrun {
189
205
  problem?.error?.message ?? `Rayrun API request failed with HTTP ${response.status}.`,
190
206
  {
191
207
  code: problem?.error?.code ?? 'request_failed',
208
+ diagnostics: Array.isArray(problem?.diagnostics) ? problem.diagnostics : [],
192
209
  requestId: problem?.error?.requestId ?? response.headers.get('rayrun-request-id'),
193
210
  status: response.status,
194
211
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rayrun/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Type-safe client for the Rayrun public API",
5
5
  "license": "MIT",
6
6
  "repository": {