Skip to content

Commit 2fb6ec5

Browse files
committed
0.3.0: Fixed TypeScript SDK, bumped packages, changed default embedding model to mixedbread-ai/mxbai-embed-large-v1
1 parent 59c894f commit 2fb6ec5

File tree

20 files changed

+2257
-512
lines changed

20 files changed

+2257
-512
lines changed

poetry.lock

Lines changed: 483 additions & 457 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "grizabella"
3-
version = "0.2.6"
3+
version = "0.2.7"
44
description = "A tri-layer memory framework for LLM solutions."
55
authors = ["Grizabella Project Contributors <contributors@example.com>"]
66
readme = "README.md"

tests/e2e/test_grizabella_mcp_e2e.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ async def _define_schema(state: E2EState):
110110
name="PaperAbstractEmbedding",
111111
object_type_name="Paper",
112112
source_property_name="abstract",
113-
embedding_model="colbert-ir/colbertv2.0",
113+
embedding_model="mixedbread-ai/mxbai-embed-large-v1",
114114
description="Embedding for the abstract of papers."
115115
)
116116
await state.session.call_tool("create_embedding_definition", {"embedding_def": paper_abstract_ed})

tests/integration/mcp/test_mcp_news_workflow.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,12 @@ async def execute_tool_call(tool_call, sessions):
8686
result = await session.call_tool(tool_name, args)
8787
return result
8888

89-
@pytest.mark.skipif(
90-
not os.getenv("TESTING_MODEL"),
91-
reason="Test model not set"
92-
)
89+
#@pytest.mark.skipif(
90+
# not os.getenv("TESTING_MODEL"),
91+
# reason="Test model not set"
92+
#)
93+
# Uncomment above and comment the next one to use the test, it's disabled by default
94+
@pytest.mark.skip
9395
@pytest.mark.asyncio
9496
async def test_news_workflow():
9597
# Create MCP clients using start_mcp_servers utility

tests/integration/test_lancedb_semantic_search.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def test_semantic_search_with_lancedb(temp_grizabella_db: Grizabella):
124124
name="content_embedding",
125125
object_type_name="TextDocument",
126126
source_property_name="content",
127-
embedding_model="colbert-ir/colbertv2.0", # Default model
127+
embedding_model="mixedbread-ai/mxbai-embed-large-v1", # Default model
128128
)
129129
gz_client.create_embedding_definition(embedding_def) # Corrected method name
130130

tests/unit/core/test_db_manager_embeddings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
from grizabella.core.exceptions import SchemaError, EmbeddingError
1818

1919
# Default HuggingFace model for tests if not overridden
20-
DEFAULT_HF_MODEL = "huggingface/colbert-ir/colbertv2.0"
21-
DEFAULT_DIMENSIONS = 128 # Assuming this for the default model
20+
DEFAULT_HF_MODEL = "huggingface/mixedbread-ai/mxbai-embed-large-v1"
21+
DEFAULT_DIMENSIONS = 512 # Assuming this for the default model
2222

2323
@pytest.fixture
2424
def mock_sqlite_adapter_instance():

tests/unit/db_layers/lancedb/test_lancedb_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def embedding_def_sample1():
4141
name="test_embedding_def_1",
4242
object_type_name="TestObject",
4343
source_property_name="text_content",
44-
embedding_model="huggingface/colbert-ir/colbertv2.0", # Example model
44+
embedding_model="huggingface/mixedbread-ai/mxbai-embed-large-v1", # Example model
4545
dimensions=128 # Example dimension
4646
)
4747

typescript/src/client/MCPClient.ts

Lines changed: 107 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -308,24 +308,40 @@ export class MCPClient {
308308
if (toolName === 'get_embedding_vector_for_text' && this.config.debug) {
309309
console.log(`About to parse result for ${toolName}. Raw result structure:`, JSON.stringify(result, null, 2));
310310
}
311-
312-
// Parse the result content
313-
// Log the actual response structure for debugging
314-
console.log(`Result from tool ${toolName}:`, JSON.stringify(result, null, 2));
315-
if (!result['result']) {
316-
// Check if the result has a different structure
317-
if (result.hasOwnProperty('content')) {
318-
return result['content'] as unknown as T;
319-
}
320-
// For void operations, return undefined
321-
if (toolName === 'create_object_type' || toolName === 'create_relation_type' ||
322-
toolName === 'upsert_object' || toolName === 'add_relation' ||
323-
toolName === 'delete_object' || toolName === 'delete_relation' ||
324-
toolName === 'delete_object_type' || toolName === 'delete_relation_type') {
325-
return undefined as unknown as T;
311+
312+
// Handle MCP protocol response format
313+
if (Array.isArray(result.content) && result.content.length > 0) {
314+
const content = result.content[0];
315+
if (content.type === 'text') {
316+
try {
317+
const parsedData = JSON.parse(content.text);
318+
return parsedData;
319+
} catch (parseError) {
320+
if (this.config.debug) {
321+
console.log(`Failed to parse MCP text content for ${toolName}:`, content.text);
322+
}
323+
throw new Error(`Failed to parse MCP text response: ${content.text}`);
326324
}
327-
throw new Error(`Empty response from tool: ${toolName}`);
325+
} else {
326+
throw new Error(`Unsupported content type: ${content.type}`);
328327
}
328+
}
329+
330+
// Legacy response format handling
331+
if (!result['result']) {
332+
// Check if the result has a different structure
333+
if (result.hasOwnProperty('content')) {
334+
return result['content'] as unknown as T;
335+
}
336+
// For void operations, return undefined
337+
if (toolName === 'create_object_type' || toolName === 'create_relation_type' ||
338+
toolName === 'upsert_object' || toolName === 'add_relation' ||
339+
toolName === 'delete_object' || toolName === 'delete_relation' ||
340+
toolName === 'delete_object_type' || toolName === 'delete_relation_type') {
341+
return undefined as unknown as T;
342+
}
343+
throw new Error(`Empty response from tool: ${toolName}`);
344+
}
329345

330346
// If result is already a string, parse it
331347
if (typeof result['result'] === 'string') {
@@ -449,44 +465,92 @@ export class MCPClient {
449465
* Creates or updates an object instance.
450466
*/
451467
async upsertObject(params: UpsertObjectParams): Promise<ObjectInstance> {
452-
return await this.callTool<ObjectInstance>('upsert_object', {
468+
const result = await this.callTool<ObjectInstance>('upsert_object', {
453469
obj: params.obj,
454470
});
471+
472+
// If the server returns undefined (bug in MCP server), try to fetch the object by ID
473+
if (!result) {
474+
if (this.config.debug) {
475+
console.warn('upsertObject returned undefined, attempting to fetch object by ID:', params.obj.id);
476+
}
477+
const fetched = await this.getObjectById({
478+
object_id: params.obj.id,
479+
type_name: params.obj.object_type_name
480+
});
481+
if (fetched) {
482+
return fetched;
483+
}
484+
throw new Error(`Failed to upsert and retrieve object ${params.obj.id}`);
485+
}
486+
487+
return result;
455488
}
456489

457490
/**
458491
* Retrieves an object instance by ID and type.
459492
*/
460-
async getObjectById(params: GetObjectByIdParams): Promise<ObjectInstance | null> {
461-
const rawResult = await this.callTool<any>('get_object_by_id', {
462-
object_id: params.object_id,
463-
type_name: params.type_name,
464-
});
465-
466-
// Debug: Log the raw result structure
467-
if (this.config.debug) {
468-
console.log('getObjectById raw result:', JSON.stringify(rawResult, null, 2));
469-
}
470-
471-
let result: ObjectInstance | null;
493+
async getObjectById(params: GetObjectByIdParams): Promise<ObjectInstance | null> {
494+
const rawResult = await this.callTool<any>('get_object_by_id', {
495+
object_id: params.object_id,
496+
type_name: params.type_name,
497+
});
498+
499+
// Debug: Log the raw result structure
500+
if (this.config.debug) {
501+
console.log('getObjectById raw result:', JSON.stringify(rawResult, null, 2));
502+
}
503+
504+
let result: ObjectInstance | null;
505+
506+
// Handle MCP protocol response format
507+
if (Array.isArray(rawResult) && rawResult.length > 0 && rawResult[0].type === 'text') {
508+
// MCP protocol format: [{"type":"text","text":"{json_string}"}]
509+
try {
510+
const parsedData = JSON.parse(rawResult[0].text);
511+
result = parsedData;
512+
} catch (parseError) {
513+
throw new Error(`Failed to parse MCP text response: ${rawResult[0].text}`);
514+
}
515+
} else if (rawResult && typeof rawResult === 'object') {
516+
// Direct format: {object_instance} or null
517+
result = rawResult as ObjectInstance | null;
518+
} else {
519+
throw new Error(`Invalid object by ID response format: ${JSON.stringify(rawResult)}`);
520+
}
521+
522+
// Deserialize datetime properties
523+
if (result && result.properties) {
524+
result.properties = this.deserializeProperties(result.properties);
525+
}
526+
527+
return result;
528+
}
472529

473-
// Handle MCP protocol response format
474-
if (Array.isArray(rawResult) && rawResult.length > 0 && rawResult[0].type === 'text') {
475-
// MCP protocol format: [{"type":"text","text":"{json_string}"}]
476-
try {
477-
const parsedData = JSON.parse(rawResult[0].text);
478-
result = parsedData;
479-
} catch (parseError) {
480-
throw new Error(`Failed to parse MCP text response: ${rawResult[0].text}`);
530+
/**
531+
* Deserializes properties, converting datetime strings to Date objects.
532+
*/
533+
private deserializeProperties(properties: Record<string, any>): Record<string, any> {
534+
const deserialized = { ...properties };
535+
536+
for (const [key, value] of Object.entries(deserialized)) {
537+
if (typeof value === 'string') {
538+
// Check if it's an ISO 8601 datetime string
539+
const isoRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/;
540+
if (isoRegex.test(value)) {
541+
try {
542+
deserialized[key] = new Date(value);
543+
} catch (dateError) {
544+
// If parsing fails, keep the original string
545+
if (this.config.debug) {
546+
console.warn(`Failed to parse datetime string '${value}' for property '${key}':`, dateError);
547+
}
548+
}
549+
}
481550
}
482-
} else if (rawResult && typeof rawResult === 'object') {
483-
// Direct format: {object_instance} or null
484-
result = rawResult as ObjectInstance | null;
485-
} else {
486-
throw new Error(`Invalid object by ID response format: ${JSON.stringify(rawResult)}`);
487551
}
488552

489-
return result;
553+
return deserialized;
490554
}
491555

492556
/**

typescript/src/types/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,4 @@ export const MIN_WEIGHT = 0.0;
165165
/**
166166
* Default embedding model identifier used by EmbeddingDefinitions.
167167
*/
168-
export const DEFAULT_EMBEDDING_MODEL = 'huggingface/colbert-ir/colbertv2.0';
168+
export const DEFAULT_EMBEDDING_MODEL = 'huggingface/mixedbread-ai/mxbai-embed-large-v1';

typescript/test-embedding-wXRJtt/embedding_test_db/kuzu_data/.lock

Whitespace-only changes.

0 commit comments

Comments
 (0)