Skip to content

Commit 9683277

Browse files
fix: adding axon sql to sdk (#760)
Co-authored-by: codeant-ai[bot] <151821869+codeant-ai[bot]@users.noreply.github.com>
1 parent 03b7479 commit 9683277

4 files changed

Lines changed: 108 additions & 4 deletions

File tree

src/resources/axons/axons.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,17 @@ export class Axons extends APIResource {
6666
* [Beta] Subscribe to an axon event stream via server-sent events.
6767
*/
6868
subscribeSse(id: string, options?: Core.RequestOptions): APIPromise<Stream<AxonEventView>> {
69-
return this._client.get(`/v1/axons/${id}/subscribe/sse`, { ...options, stream: true }) as APIPromise<
70-
Stream<AxonEventView>
71-
>;
69+
const mergedOptions: Core.RequestOptions = {
70+
...options,
71+
headers: {
72+
Accept: 'text/event-stream',
73+
...options?.headers,
74+
},
75+
};
76+
return this._client.get(`/v1/axons/${id}/subscribe/sse`, {
77+
...mergedOptions,
78+
stream: true,
79+
}) as APIPromise<Stream<AxonEventView>>;
7280
}
7381
}
7482

src/sdk/axon.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,50 @@ import type {
88
PublishResultView,
99
AxonEventView,
1010
} from '../resources/axons';
11+
import type {
12+
SqlBatchParams,
13+
SqlBatchResultView,
14+
SqlQueryParams,
15+
SqlQueryResultView,
16+
} from '../resources/axons/sql';
17+
18+
/**
19+
* SQL operations for an axon's SQLite database.
20+
*
21+
* @category Axon
22+
*/
23+
export class AxonSqlOps {
24+
/**
25+
* @private
26+
*/
27+
constructor(
28+
private client: Runloop,
29+
private axonId: string,
30+
) {}
31+
32+
/**
33+
* [Beta] Execute a single parameterized SQL statement against this axon's SQLite database.
34+
*
35+
* @param {SqlQueryParams} params - The SQL query and optional positional parameters
36+
* @param {Core.RequestOptions} [options] - Request options
37+
* @returns {Promise<SqlQueryResultView>} The query result with columns, rows, and metadata
38+
*/
39+
async query(params: SqlQueryParams, options?: Core.RequestOptions): Promise<SqlQueryResultView> {
40+
return this.client.axons.sql.query(this.axonId, params, options);
41+
}
42+
43+
/**
44+
* [Beta] Execute multiple SQL statements atomically within a single transaction
45+
* against this axon's SQLite database.
46+
*
47+
* @param {SqlBatchParams} params - The batch of SQL statements to execute
48+
* @param {Core.RequestOptions} [options] - Request options
49+
* @returns {Promise<SqlBatchResultView>} One result per statement, in order
50+
*/
51+
async batch(params: SqlBatchParams, options?: Core.RequestOptions): Promise<SqlBatchResultView> {
52+
return this.client.axons.sql.batch(this.axonId, params, options);
53+
}
54+
}
1155

1256
/**
1357
* [Beta] Object-oriented interface for working with Axons.
@@ -42,15 +86,21 @@ import type {
4286
* for await (const event of stream) {
4387
* console.log(event.event_type, event.payload);
4488
* }
89+
*
90+
* // Execute SQL queries
91+
* await axon.sql.query({ sql: 'CREATE TABLE tasks (id INTEGER PRIMARY KEY, name TEXT)' });
92+
* const result = await axon.sql.query({ sql: 'SELECT * FROM tasks WHERE id = ?', params: [1] });
4593
* ```
4694
*/
4795
export class Axon {
4896
private client: Runloop;
4997
private _id: string;
98+
public readonly sql: AxonSqlOps;
5099

51100
private constructor(client: Runloop, id: string) {
52101
this.client = client;
53102
this._id = id;
103+
this.sql = new AxonSqlOps(this.client, this._id);
54104
}
55105

56106
/**

src/sdk/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export { Blueprint } from './blueprint';
33
export { Snapshot } from './snapshot';
44
export { StorageObject } from './storage-object';
55
export { Agent } from './agent';
6-
export { Axon } from './axon';
6+
export { Axon, AxonSqlOps } from './axon';
77
export { Execution } from './execution';
88
export { ExecutionResult } from './execution-result';
99
export { Scorer } from './scorer';

tests/smoketests/object-oriented/axon.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ const sdk = makeClientSDK();
7777
});
7878

7979
test('subscribe to SSE stream and receive events', async () => {
80+
// Ensure at least one event exists so the stream has something to replay
81+
await axon.publish({
82+
event_type: 'sse_test',
83+
origin: 'USER_EVENT',
84+
payload: JSON.stringify({ sse: true }),
85+
source: 'sdk-smoke-test',
86+
});
87+
8088
const stream = await axon.subscribeSse();
8189
const events = [];
8290
for await (const event of stream) {
@@ -91,6 +99,44 @@ const sdk = makeClientSDK();
9199
expect(first.payload).toBeDefined();
92100
expect(first.sequence).toBeGreaterThanOrEqual(0);
93101
});
102+
103+
test('sql.query: create table and insert row', async () => {
104+
await axon.sql.query({
105+
sql: 'CREATE TABLE IF NOT EXISTS smoke_test (id INTEGER PRIMARY KEY, value TEXT)',
106+
});
107+
108+
await axon.sql.query({
109+
sql: 'INSERT INTO smoke_test (id, value) VALUES (?, ?)',
110+
params: [1, 'hello'],
111+
});
112+
113+
const result = await axon.sql.query({
114+
sql: 'SELECT * FROM smoke_test WHERE id = ?',
115+
params: [1],
116+
});
117+
118+
expect(result.columns).toBeDefined();
119+
expect(result.columns.length).toBeGreaterThan(0);
120+
expect(result.rows.length).toBe(1);
121+
expect(result.meta.duration_ms).toBeGreaterThanOrEqual(0);
122+
});
123+
124+
test('sql.batch: execute multiple statements atomically', async () => {
125+
const result = await axon.sql.batch({
126+
statements: [
127+
{ sql: 'CREATE TABLE IF NOT EXISTS batch_test (id INTEGER PRIMARY KEY, name TEXT)' },
128+
{ sql: 'INSERT INTO batch_test (id, name) VALUES (?, ?)', params: [1, 'alice'] },
129+
{ sql: 'INSERT INTO batch_test (id, name) VALUES (?, ?)', params: [2, 'bob'] },
130+
{ sql: 'SELECT * FROM batch_test ORDER BY id' },
131+
],
132+
});
133+
134+
expect(result.results).toBeDefined();
135+
expect(result.results.length).toBe(4);
136+
const selectResult = result.results[3]!;
137+
expect(selectResult.success).toBeDefined();
138+
expect(selectResult.success!.rows.length).toBe(2);
139+
});
94140
});
95141

96142
describe('axon list', () => {

0 commit comments

Comments
 (0)