@constructive-io/graphql-server 4.32.0 → 4.33.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.
@@ -23,39 +23,10 @@
23
23
  import express, { Router } from 'express';
24
24
  import { Logger } from '@pgpmjs/logger';
25
25
  import { getPgPool } from 'pg-cache';
26
- import OllamaClient from '@agentic-kit/ollama';
26
+ import { OllamaAdapter } from '@agentic-kit/ollama';
27
27
  import { ModuleConfigCache } from 'graphile-cache';
28
28
  import { getLlmEnvOptions, getAgentDiscovery, getLlmBillingConfig, } from 'graphile-llm';
29
29
  const log = new Logger('llm-api');
30
- /**
31
- * Placeholder: replace with actual provider token counts once generateWithUsage() is approved.
32
- * Estimates ~4 chars per token for English text.
33
- */
34
- function placeholderAmountTokens(text) {
35
- return Math.ceil(text.length / 4);
36
- }
37
- /**
38
- * Call generate() and estimate token counts from text length.
39
- * When a provider-native token counting API is approved, swap the
40
- * estimation logic here without changing call sites.
41
- */
42
- async function callWithUsage(client, input, onChunk) {
43
- const promptText = input.messages.map((m) => m.content).join(' ');
44
- let content;
45
- if (onChunk || input.stream) {
46
- await client.generate(input, onChunk);
47
- content = '';
48
- }
49
- else {
50
- content = await client.generate(input);
51
- }
52
- const inputTokens = placeholderAmountTokens(promptText);
53
- const outputTokens = placeholderAmountTokens(content);
54
- return {
55
- content,
56
- usage: { input: inputTokens, output: outputTokens, totalTokens: inputTokens + outputTokens },
57
- };
58
- }
59
30
  // ─── Helpers ────────────────────────────────────────────────────────────────
60
31
  function getPgSettings(req) {
61
32
  const settings = {};
@@ -90,12 +61,13 @@ async function withRlsClient(pool, pgSettings, fn) {
90
61
  client.release();
91
62
  }
92
63
  }
93
- function resolveOllamaClient() {
64
+ function resolveOllamaAdapter() {
94
65
  const { chat } = getLlmEnvOptions();
95
66
  if (chat.provider === 'ollama') {
96
67
  return {
97
- client: new OllamaClient(chat.baseUrl),
68
+ adapter: new OllamaAdapter(chat.baseUrl),
98
69
  model: chat.model,
70
+ baseUrl: chat.baseUrl,
99
71
  };
100
72
  }
101
73
  return null;
@@ -280,7 +252,7 @@ async function handleSendMessage(req, res, entityId) {
280
252
  ? await resolveBilling(pool, pgSettings, databaseId)
281
253
  : null;
282
254
  const inferenceLog = await getInferenceLogInfo(pool, dbname);
283
- const ollama = resolveOllamaClient();
255
+ const ollama = resolveOllamaAdapter();
284
256
  if (!ollama) {
285
257
  res.status(503).json({ error: 'No LLM provider configured' });
286
258
  return;
@@ -343,7 +315,7 @@ async function handleSendMessage(req, res, entityId) {
343
315
  const shouldStream = body.stream !== false;
344
316
  const startTime = Date.now();
345
317
  if (shouldStream) {
346
- // ── SSE Streaming ──────────────────────────────────────────────────
318
+ // ── SSE Streaming via OllamaAdapter ─────────────────────────────────
347
319
  res.writeHead(200, {
348
320
  'Content-Type': 'text/event-stream',
349
321
  'Cache-Control': 'no-cache',
@@ -352,32 +324,49 @@ async function handleSendMessage(req, res, entityId) {
352
324
  });
353
325
  const messageId = `msg_${Date.now()}`;
354
326
  try {
355
- let streamedContent = '';
356
- const result = await callWithUsage(ollama.client, {
357
- model,
358
- messages: llmMessages,
359
- stream: true,
327
+ const systemMsg = llmMessages.find(m => m.role === 'system');
328
+ const nonSystem = llmMessages.filter(m => m.role !== 'system');
329
+ const modelDesc = ollama.adapter.createModel(model, {
330
+ maxOutputTokens: undefined,
331
+ });
332
+ const context = {
333
+ systemPrompt: systemMsg?.content,
334
+ messages: nonSystem.map((m) => ({
335
+ role: m.role,
336
+ content: m.content,
337
+ timestamp: Date.now(),
338
+ })),
339
+ };
340
+ const stream = ollama.adapter.stream(modelDesc, context, {
360
341
  temperature: body.temperature,
361
- }, (chunk) => {
362
- streamedContent += chunk;
363
- const event = {
364
- id: messageId,
365
- choices: [{
366
- index: 0,
367
- delta: { content: chunk, role: 'assistant' },
368
- finish_reason: null,
369
- }],
370
- model,
371
- };
372
- res.write(`data: ${JSON.stringify(event)}\n\n`);
373
342
  });
374
- // Streaming generate() returns void; use accumulated chunks
343
+ let streamedContent = '';
344
+ for await (const event of stream) {
345
+ if (event.type === 'text_delta') {
346
+ streamedContent += event.delta;
347
+ const sseEvent = {
348
+ id: messageId,
349
+ choices: [{
350
+ index: 0,
351
+ delta: { content: event.delta, role: 'assistant' },
352
+ finish_reason: null,
353
+ }],
354
+ model,
355
+ };
356
+ res.write(`data: ${JSON.stringify(sseEvent)}\n\n`);
357
+ }
358
+ }
359
+ const result = await stream.result();
375
360
  const content = streamedContent;
376
- const promptText = llmMessages.map(m => m.content).join(' ');
377
361
  const latencyMs = Date.now() - startTime;
378
- const inputTokens = placeholderAmountTokens(promptText);
379
- const outputTokens = placeholderAmountTokens(content);
380
- const totalTokens = inputTokens + outputTokens;
362
+ const usage = {
363
+ input: result.usage.input,
364
+ output: result.usage.output,
365
+ reasoning: result.usage.reasoning,
366
+ cacheRead: result.usage.cacheRead,
367
+ cacheWrite: result.usage.cacheWrite,
368
+ totalTokens: result.usage.totalTokens,
369
+ };
381
370
  // Send [DONE] marker
382
371
  res.write('data: [DONE]\n\n');
383
372
  res.end();
@@ -398,10 +387,12 @@ async function handleSendMessage(req, res, entityId) {
398
387
  });
399
388
  }
400
389
  // 7. Record billing usage (fire-and-forget)
401
- if (billing && totalTokens > 0) {
402
- recordUsage(pool, pgSettings, billing, entityId, meterSlug, totalTokens, {
403
- input_tokens: inputTokens,
404
- output_tokens: outputTokens,
390
+ if (billing && usage.totalTokens > 0) {
391
+ recordUsage(pool, pgSettings, billing, entityId, meterSlug, usage.totalTokens, {
392
+ input_tokens: usage.input,
393
+ output_tokens: usage.output,
394
+ cache_read_tokens: usage.cacheRead,
395
+ cache_write_tokens: usage.cacheWrite,
405
396
  model,
406
397
  latency_ms: latencyMs,
407
398
  stream: true,
@@ -416,9 +407,9 @@ async function handleSendMessage(req, res, entityId) {
416
407
  provider: 'ollama',
417
408
  service: 'llm',
418
409
  operation: 'chat',
419
- inputTokens,
420
- outputTokens,
421
- totalTokens,
410
+ inputTokens: usage.input,
411
+ outputTokens: usage.output,
412
+ totalTokens: usage.totalTokens,
422
413
  latencyMs,
423
414
  status: 'ok',
424
415
  }).catch(() => { });
@@ -433,17 +424,37 @@ async function handleSendMessage(req, res, entityId) {
433
424
  }
434
425
  }
435
426
  else {
436
- // ── Non-streaming (batch) ──────────────────────────────────────────
437
- const result = await callWithUsage(ollama.client, {
438
- model,
439
- messages: llmMessages,
440
- stream: false,
427
+ // ── Non-streaming (batch) via OllamaAdapter ─────────────────────────
428
+ const systemMsg = llmMessages.find(m => m.role === 'system');
429
+ const nonSystem = llmMessages.filter(m => m.role !== 'system');
430
+ const modelDesc = ollama.adapter.createModel(model, {
431
+ maxOutputTokens: undefined,
432
+ });
433
+ const context = {
434
+ systemPrompt: systemMsg?.content,
435
+ messages: nonSystem.map((m) => ({
436
+ role: m.role,
437
+ content: m.content,
438
+ timestamp: Date.now(),
439
+ })),
440
+ };
441
+ const stream = ollama.adapter.stream(modelDesc, context, {
441
442
  temperature: body.temperature,
442
443
  });
444
+ const result = await stream.result();
445
+ const content = result.content
446
+ .filter((block) => block.type === 'text')
447
+ .map((block) => block.text)
448
+ .join('');
443
449
  const latencyMs = Date.now() - startTime;
444
- const inputTokens = result.usage.input;
445
- const outputTokens = result.usage.output;
446
- const totalTokens = result.usage.totalTokens;
450
+ const usage = {
451
+ input: result.usage.input,
452
+ output: result.usage.output,
453
+ reasoning: result.usage.reasoning,
454
+ cacheRead: result.usage.cacheRead,
455
+ cacheWrite: result.usage.cacheWrite,
456
+ totalTokens: result.usage.totalTokens,
457
+ };
447
458
  // Persist assistant message with model
448
459
  await withRlsClient(pool, pgSettings, async (client) => {
449
460
  await client.query(`INSERT INTO "${msgTable.schemaName}"."${msgTable.tableName}"
@@ -452,15 +463,17 @@ async function handleSendMessage(req, res, entityId) {
452
463
  threadId,
453
464
  userId,
454
465
  'assistant',
455
- JSON.stringify([{ type: 'text', text: result.content }]),
466
+ JSON.stringify([{ type: 'text', text: content }]),
456
467
  model,
457
468
  ]);
458
469
  });
459
470
  // Record billing usage
460
- if (billing && totalTokens > 0) {
461
- recordUsage(pool, pgSettings, billing, entityId, meterSlug, totalTokens, {
462
- input_tokens: inputTokens,
463
- output_tokens: outputTokens,
471
+ if (billing && usage.totalTokens > 0) {
472
+ recordUsage(pool, pgSettings, billing, entityId, meterSlug, usage.totalTokens, {
473
+ input_tokens: usage.input,
474
+ output_tokens: usage.output,
475
+ cache_read_tokens: usage.cacheRead,
476
+ cache_write_tokens: usage.cacheWrite,
464
477
  model,
465
478
  latency_ms: latencyMs,
466
479
  stream: false,
@@ -475,9 +488,9 @@ async function handleSendMessage(req, res, entityId) {
475
488
  provider: 'ollama',
476
489
  service: 'llm',
477
490
  operation: 'chat',
478
- inputTokens,
479
- outputTokens,
480
- totalTokens,
491
+ inputTokens: usage.input,
492
+ outputTokens: usage.output,
493
+ totalTokens: usage.totalTokens,
481
494
  latencyMs,
482
495
  status: 'ok',
483
496
  }).catch(() => { });
@@ -486,14 +499,14 @@ async function handleSendMessage(req, res, entityId) {
486
499
  id: `msg_${Date.now()}`,
487
500
  choices: [{
488
501
  index: 0,
489
- message: { role: 'assistant', content: result.content },
502
+ message: { role: 'assistant', content },
490
503
  finish_reason: 'stop',
491
504
  }],
492
505
  model,
493
506
  usage: {
494
- prompt_tokens: inputTokens,
495
- completion_tokens: outputTokens,
496
- total_tokens: totalTokens,
507
+ prompt_tokens: usage.input,
508
+ completion_tokens: usage.output,
509
+ total_tokens: usage.totalTokens,
497
510
  },
498
511
  });
499
512
  }
@@ -54,47 +54,15 @@ var __importStar = (this && this.__importStar) || (function () {
54
54
  return result;
55
55
  };
56
56
  })();
57
- var __importDefault = (this && this.__importDefault) || function (mod) {
58
- return (mod && mod.__esModule) ? mod : { "default": mod };
59
- };
60
57
  Object.defineProperty(exports, "__esModule", { value: true });
61
58
  exports.createLlmApiRouter = createLlmApiRouter;
62
59
  const express_1 = __importStar(require("express"));
63
60
  const logger_1 = require("@pgpmjs/logger");
64
61
  const pg_cache_1 = require("pg-cache");
65
- const ollama_1 = __importDefault(require("@agentic-kit/ollama"));
62
+ const ollama_1 = require("@agentic-kit/ollama");
66
63
  const graphile_cache_1 = require("graphile-cache");
67
64
  const graphile_llm_1 = require("graphile-llm");
68
65
  const log = new logger_1.Logger('llm-api');
69
- /**
70
- * Placeholder: replace with actual provider token counts once generateWithUsage() is approved.
71
- * Estimates ~4 chars per token for English text.
72
- */
73
- function placeholderAmountTokens(text) {
74
- return Math.ceil(text.length / 4);
75
- }
76
- /**
77
- * Call generate() and estimate token counts from text length.
78
- * When a provider-native token counting API is approved, swap the
79
- * estimation logic here without changing call sites.
80
- */
81
- async function callWithUsage(client, input, onChunk) {
82
- const promptText = input.messages.map((m) => m.content).join(' ');
83
- let content;
84
- if (onChunk || input.stream) {
85
- await client.generate(input, onChunk);
86
- content = '';
87
- }
88
- else {
89
- content = await client.generate(input);
90
- }
91
- const inputTokens = placeholderAmountTokens(promptText);
92
- const outputTokens = placeholderAmountTokens(content);
93
- return {
94
- content,
95
- usage: { input: inputTokens, output: outputTokens, totalTokens: inputTokens + outputTokens },
96
- };
97
- }
98
66
  // ─── Helpers ────────────────────────────────────────────────────────────────
99
67
  function getPgSettings(req) {
100
68
  const settings = {};
@@ -129,12 +97,13 @@ async function withRlsClient(pool, pgSettings, fn) {
129
97
  client.release();
130
98
  }
131
99
  }
132
- function resolveOllamaClient() {
100
+ function resolveOllamaAdapter() {
133
101
  const { chat } = (0, graphile_llm_1.getLlmEnvOptions)();
134
102
  if (chat.provider === 'ollama') {
135
103
  return {
136
- client: new ollama_1.default(chat.baseUrl),
104
+ adapter: new ollama_1.OllamaAdapter(chat.baseUrl),
137
105
  model: chat.model,
106
+ baseUrl: chat.baseUrl,
138
107
  };
139
108
  }
140
109
  return null;
@@ -319,7 +288,7 @@ async function handleSendMessage(req, res, entityId) {
319
288
  ? await resolveBilling(pool, pgSettings, databaseId)
320
289
  : null;
321
290
  const inferenceLog = await getInferenceLogInfo(pool, dbname);
322
- const ollama = resolveOllamaClient();
291
+ const ollama = resolveOllamaAdapter();
323
292
  if (!ollama) {
324
293
  res.status(503).json({ error: 'No LLM provider configured' });
325
294
  return;
@@ -382,7 +351,7 @@ async function handleSendMessage(req, res, entityId) {
382
351
  const shouldStream = body.stream !== false;
383
352
  const startTime = Date.now();
384
353
  if (shouldStream) {
385
- // ── SSE Streaming ──────────────────────────────────────────────────
354
+ // ── SSE Streaming via OllamaAdapter ─────────────────────────────────
386
355
  res.writeHead(200, {
387
356
  'Content-Type': 'text/event-stream',
388
357
  'Cache-Control': 'no-cache',
@@ -391,32 +360,49 @@ async function handleSendMessage(req, res, entityId) {
391
360
  });
392
361
  const messageId = `msg_${Date.now()}`;
393
362
  try {
394
- let streamedContent = '';
395
- const result = await callWithUsage(ollama.client, {
396
- model,
397
- messages: llmMessages,
398
- stream: true,
363
+ const systemMsg = llmMessages.find(m => m.role === 'system');
364
+ const nonSystem = llmMessages.filter(m => m.role !== 'system');
365
+ const modelDesc = ollama.adapter.createModel(model, {
366
+ maxOutputTokens: undefined,
367
+ });
368
+ const context = {
369
+ systemPrompt: systemMsg?.content,
370
+ messages: nonSystem.map((m) => ({
371
+ role: m.role,
372
+ content: m.content,
373
+ timestamp: Date.now(),
374
+ })),
375
+ };
376
+ const stream = ollama.adapter.stream(modelDesc, context, {
399
377
  temperature: body.temperature,
400
- }, (chunk) => {
401
- streamedContent += chunk;
402
- const event = {
403
- id: messageId,
404
- choices: [{
405
- index: 0,
406
- delta: { content: chunk, role: 'assistant' },
407
- finish_reason: null,
408
- }],
409
- model,
410
- };
411
- res.write(`data: ${JSON.stringify(event)}\n\n`);
412
378
  });
413
- // Streaming generate() returns void; use accumulated chunks
379
+ let streamedContent = '';
380
+ for await (const event of stream) {
381
+ if (event.type === 'text_delta') {
382
+ streamedContent += event.delta;
383
+ const sseEvent = {
384
+ id: messageId,
385
+ choices: [{
386
+ index: 0,
387
+ delta: { content: event.delta, role: 'assistant' },
388
+ finish_reason: null,
389
+ }],
390
+ model,
391
+ };
392
+ res.write(`data: ${JSON.stringify(sseEvent)}\n\n`);
393
+ }
394
+ }
395
+ const result = await stream.result();
414
396
  const content = streamedContent;
415
- const promptText = llmMessages.map(m => m.content).join(' ');
416
397
  const latencyMs = Date.now() - startTime;
417
- const inputTokens = placeholderAmountTokens(promptText);
418
- const outputTokens = placeholderAmountTokens(content);
419
- const totalTokens = inputTokens + outputTokens;
398
+ const usage = {
399
+ input: result.usage.input,
400
+ output: result.usage.output,
401
+ reasoning: result.usage.reasoning,
402
+ cacheRead: result.usage.cacheRead,
403
+ cacheWrite: result.usage.cacheWrite,
404
+ totalTokens: result.usage.totalTokens,
405
+ };
420
406
  // Send [DONE] marker
421
407
  res.write('data: [DONE]\n\n');
422
408
  res.end();
@@ -437,10 +423,12 @@ async function handleSendMessage(req, res, entityId) {
437
423
  });
438
424
  }
439
425
  // 7. Record billing usage (fire-and-forget)
440
- if (billing && totalTokens > 0) {
441
- recordUsage(pool, pgSettings, billing, entityId, meterSlug, totalTokens, {
442
- input_tokens: inputTokens,
443
- output_tokens: outputTokens,
426
+ if (billing && usage.totalTokens > 0) {
427
+ recordUsage(pool, pgSettings, billing, entityId, meterSlug, usage.totalTokens, {
428
+ input_tokens: usage.input,
429
+ output_tokens: usage.output,
430
+ cache_read_tokens: usage.cacheRead,
431
+ cache_write_tokens: usage.cacheWrite,
444
432
  model,
445
433
  latency_ms: latencyMs,
446
434
  stream: true,
@@ -455,9 +443,9 @@ async function handleSendMessage(req, res, entityId) {
455
443
  provider: 'ollama',
456
444
  service: 'llm',
457
445
  operation: 'chat',
458
- inputTokens,
459
- outputTokens,
460
- totalTokens,
446
+ inputTokens: usage.input,
447
+ outputTokens: usage.output,
448
+ totalTokens: usage.totalTokens,
461
449
  latencyMs,
462
450
  status: 'ok',
463
451
  }).catch(() => { });
@@ -472,17 +460,37 @@ async function handleSendMessage(req, res, entityId) {
472
460
  }
473
461
  }
474
462
  else {
475
- // ── Non-streaming (batch) ──────────────────────────────────────────
476
- const result = await callWithUsage(ollama.client, {
477
- model,
478
- messages: llmMessages,
479
- stream: false,
463
+ // ── Non-streaming (batch) via OllamaAdapter ─────────────────────────
464
+ const systemMsg = llmMessages.find(m => m.role === 'system');
465
+ const nonSystem = llmMessages.filter(m => m.role !== 'system');
466
+ const modelDesc = ollama.adapter.createModel(model, {
467
+ maxOutputTokens: undefined,
468
+ });
469
+ const context = {
470
+ systemPrompt: systemMsg?.content,
471
+ messages: nonSystem.map((m) => ({
472
+ role: m.role,
473
+ content: m.content,
474
+ timestamp: Date.now(),
475
+ })),
476
+ };
477
+ const stream = ollama.adapter.stream(modelDesc, context, {
480
478
  temperature: body.temperature,
481
479
  });
480
+ const result = await stream.result();
481
+ const content = result.content
482
+ .filter((block) => block.type === 'text')
483
+ .map((block) => block.text)
484
+ .join('');
482
485
  const latencyMs = Date.now() - startTime;
483
- const inputTokens = result.usage.input;
484
- const outputTokens = result.usage.output;
485
- const totalTokens = result.usage.totalTokens;
486
+ const usage = {
487
+ input: result.usage.input,
488
+ output: result.usage.output,
489
+ reasoning: result.usage.reasoning,
490
+ cacheRead: result.usage.cacheRead,
491
+ cacheWrite: result.usage.cacheWrite,
492
+ totalTokens: result.usage.totalTokens,
493
+ };
486
494
  // Persist assistant message with model
487
495
  await withRlsClient(pool, pgSettings, async (client) => {
488
496
  await client.query(`INSERT INTO "${msgTable.schemaName}"."${msgTable.tableName}"
@@ -491,15 +499,17 @@ async function handleSendMessage(req, res, entityId) {
491
499
  threadId,
492
500
  userId,
493
501
  'assistant',
494
- JSON.stringify([{ type: 'text', text: result.content }]),
502
+ JSON.stringify([{ type: 'text', text: content }]),
495
503
  model,
496
504
  ]);
497
505
  });
498
506
  // Record billing usage
499
- if (billing && totalTokens > 0) {
500
- recordUsage(pool, pgSettings, billing, entityId, meterSlug, totalTokens, {
501
- input_tokens: inputTokens,
502
- output_tokens: outputTokens,
507
+ if (billing && usage.totalTokens > 0) {
508
+ recordUsage(pool, pgSettings, billing, entityId, meterSlug, usage.totalTokens, {
509
+ input_tokens: usage.input,
510
+ output_tokens: usage.output,
511
+ cache_read_tokens: usage.cacheRead,
512
+ cache_write_tokens: usage.cacheWrite,
503
513
  model,
504
514
  latency_ms: latencyMs,
505
515
  stream: false,
@@ -514,9 +524,9 @@ async function handleSendMessage(req, res, entityId) {
514
524
  provider: 'ollama',
515
525
  service: 'llm',
516
526
  operation: 'chat',
517
- inputTokens,
518
- outputTokens,
519
- totalTokens,
527
+ inputTokens: usage.input,
528
+ outputTokens: usage.output,
529
+ totalTokens: usage.totalTokens,
520
530
  latencyMs,
521
531
  status: 'ok',
522
532
  }).catch(() => { });
@@ -525,14 +535,14 @@ async function handleSendMessage(req, res, entityId) {
525
535
  id: `msg_${Date.now()}`,
526
536
  choices: [{
527
537
  index: 0,
528
- message: { role: 'assistant', content: result.content },
538
+ message: { role: 'assistant', content },
529
539
  finish_reason: 'stop',
530
540
  }],
531
541
  model,
532
542
  usage: {
533
- prompt_tokens: inputTokens,
534
- completion_tokens: outputTokens,
535
- total_tokens: totalTokens,
543
+ prompt_tokens: usage.input,
544
+ completion_tokens: usage.output,
545
+ total_tokens: usage.totalTokens,
536
546
  },
537
547
  });
538
548
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-server",
3
- "version": "4.32.0",
3
+ "version": "4.33.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "Constructive GraphQL Server",
6
6
  "main": "index.js",
@@ -41,7 +41,7 @@
41
41
  "backend"
42
42
  ],
43
43
  "dependencies": {
44
- "@agentic-kit/ollama": "^1.2.1",
44
+ "@agentic-kit/ollama": "^2.0.0",
45
45
  "@constructive-io/csrf": "^0.14.0",
46
46
  "@constructive-io/graphql-env": "^3.11.1",
47
47
  "@constructive-io/graphql-types": "^3.10.1",
@@ -64,7 +64,7 @@
64
64
  "graphile-build-pg": "5.0.2",
65
65
  "graphile-cache": "^3.11.2",
66
66
  "graphile-config": "1.0.1",
67
- "graphile-llm": "^0.8.0",
67
+ "graphile-llm": "^0.9.0",
68
68
  "graphile-settings": "^5.2.4",
69
69
  "graphile-utils": "5.0.1",
70
70
  "graphql": "16.13.0",
@@ -94,5 +94,5 @@
94
94
  "nodemon": "^3.1.14",
95
95
  "ts-node": "^10.9.2"
96
96
  },
97
- "gitHead": "030e1144acbd4e288ee74eff2ac0021ca0382ef7"
97
+ "gitHead": "f3ea414974306e3c0d1d68edc93b4cdd8fa6e806"
98
98
  }