Skip to content

Commit 44fec2e

Browse files
authored
feat: add Dart SDK for Alphahuman Memory API (#12)
1 parent 4901b5e commit 44fec2e

12 files changed

Lines changed: 892 additions & 0 deletions

packages/sdk-dart/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.dart_tool/
2+
.packages
3+
build/
4+
pubspec.lock

packages/sdk-dart/.gitkeep

Whitespace-only changes.

packages/sdk-dart/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.PHONY: build test integration-test clean
2+
3+
build:
4+
dart analyze
5+
6+
test:
7+
dart test test/alphahuman_memory_client_test.dart
8+
9+
integration-test:
10+
dart test test/integration_test.dart
11+
12+
clean:
13+
rm -rf .dart_tool build
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include: package:lints/recommended.yaml
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import 'dart:io' show Platform;
2+
3+
import 'package:alphahuman_sdk/alphahuman_sdk.dart';
4+
5+
Future<void> main() async {
6+
final token = Platform.environment['ALPHAHUMAN_TOKEN'];
7+
if (token == null || token.isEmpty) {
8+
print('Set ALPHAHUMAN_TOKEN environment variable to run this example.');
9+
return;
10+
}
11+
12+
final client = AlphahumanMemoryClient(token);
13+
14+
try {
15+
// Insert a memory
16+
final insertResp = await client.insertMemory(InsertMemoryParams(
17+
title: 'example-doc',
18+
content: 'Dart was created by Google and first appeared in 2011.',
19+
namespace: 'example-ns',
20+
));
21+
print('Insert: success=${insertResp.success}, status=${insertResp.status}');
22+
23+
// Recall context
24+
final recallResp = await client.recallMemory(
25+
RecallMemoryParams(namespace: 'example-ns'));
26+
print('Recall: success=${recallResp.success}, cached=${recallResp.cached}');
27+
28+
// Query memory
29+
final queryResp = await client.queryMemory(QueryMemoryParams(
30+
query: 'When was Dart created?',
31+
namespace: 'example-ns',
32+
));
33+
print('Query: success=${queryResp.success}, response=${queryResp.response}');
34+
35+
// Recall memories (Ebbinghaus)
36+
final memoriesResp = await client.recallMemories(
37+
RecallMemoriesParams(namespace: 'example-ns'));
38+
print('Memories: success=${memoriesResp.success}, '
39+
'count=${memoriesResp.memories.length}');
40+
41+
// Delete memory
42+
final deleteResp = await client.deleteMemory(
43+
DeleteMemoryParams(namespace: 'example-ns'));
44+
print('Delete: success=${deleteResp.success}, '
45+
'nodesDeleted=${deleteResp.nodesDeleted}');
46+
} finally {
47+
client.close();
48+
}
49+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
library alphahuman_sdk;
2+
3+
export 'src/alphahuman_error.dart';
4+
export 'src/types.dart';
5+
export 'src/alphahuman_memory_client.dart';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class AlphahumanError implements Exception {
2+
final String message;
3+
final int status;
4+
final String body;
5+
6+
AlphahumanError(this.message, this.status, [this.body = '']);
7+
8+
@override
9+
String toString() => 'AlphahumanError($status): $message';
10+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import 'dart:convert';
2+
import 'dart:io' show Platform;
3+
4+
import 'package:http/http.dart' as http;
5+
6+
import 'alphahuman_error.dart';
7+
import 'types.dart';
8+
9+
class AlphahumanMemoryClient {
10+
static const _defaultBaseUrl = 'https://staging-api.alphahuman.xyz';
11+
12+
final String _token;
13+
final String _baseUrl;
14+
final http.Client _httpClient;
15+
final bool _ownsClient;
16+
17+
AlphahumanMemoryClient(
18+
String token, {
19+
String? baseUrl,
20+
http.Client? httpClient,
21+
}) : _token = token,
22+
_baseUrl = (baseUrl ??
23+
Platform.environment['ALPHAHUMAN_BASE_URL'] ??
24+
_defaultBaseUrl)
25+
.replaceAll(RegExp(r'/+$'), ''),
26+
_httpClient = httpClient ?? http.Client(),
27+
_ownsClient = httpClient == null {
28+
if (token.trim().isEmpty) {
29+
throw ArgumentError('token is required');
30+
}
31+
}
32+
33+
Future<InsertMemoryResponse> insertMemory(InsertMemoryParams params) async {
34+
params.validate();
35+
final result = await _post('/v1/memory/insert', params.toJson());
36+
return InsertMemoryResponse.fromJson(result);
37+
}
38+
39+
Future<RecallMemoryResponse> recallMemory([RecallMemoryParams? params]) async {
40+
params ??= RecallMemoryParams();
41+
params.validate();
42+
final result = await _post('/v1/memory/recall', params.toJson());
43+
return RecallMemoryResponse.fromJson(result);
44+
}
45+
46+
Future<DeleteMemoryResponse> deleteMemory([DeleteMemoryParams? params]) async {
47+
params ??= DeleteMemoryParams();
48+
params.validate();
49+
final result = await _post('/v1/memory/admin/delete', params.toJson());
50+
return DeleteMemoryResponse.fromJson(result);
51+
}
52+
53+
Future<QueryMemoryResponse> queryMemory(QueryMemoryParams params) async {
54+
params.validate();
55+
final result = await _post('/v1/memory/query', params.toJson());
56+
return QueryMemoryResponse.fromJson(result);
57+
}
58+
59+
Future<RecallMemoriesResponse> recallMemories(
60+
[RecallMemoriesParams? params]) async {
61+
params ??= RecallMemoriesParams();
62+
params.validate();
63+
final result = await _post('/v1/memory/memories/recall', params.toJson());
64+
return RecallMemoriesResponse.fromJson(result);
65+
}
66+
67+
Future<Map<String, dynamic>> _post(
68+
String path, Map<String, dynamic> body) async {
69+
final url = Uri.parse('$_baseUrl$path');
70+
final response = await _httpClient.post(
71+
url,
72+
headers: {
73+
'Content-Type': 'application/json',
74+
'Authorization': 'Bearer $_token',
75+
},
76+
body: jsonEncode(body),
77+
);
78+
return _handleResponse(response);
79+
}
80+
81+
Map<String, dynamic> _handleResponse(http.Response response) {
82+
Map<String, dynamic> json;
83+
try {
84+
json = response.body.isNotEmpty
85+
? jsonDecode(response.body) as Map<String, dynamic>
86+
: <String, dynamic>{};
87+
} catch (_) {
88+
throw AlphahumanError(
89+
'HTTP ${response.statusCode}: non-JSON response',
90+
response.statusCode,
91+
response.body,
92+
);
93+
}
94+
95+
if (response.statusCode < 200 || response.statusCode >= 300) {
96+
final message =
97+
json['error'] as String? ?? 'HTTP ${response.statusCode}';
98+
throw AlphahumanError(message, response.statusCode, response.body);
99+
}
100+
101+
return json;
102+
}
103+
104+
void close() {
105+
if (_ownsClient) {
106+
_httpClient.close();
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)