stratagate-dsh 0.3.13 → 0.3.15

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.
package/dist/plugin.js CHANGED
@@ -1689,6 +1689,7 @@ var PROFILE_FIELDS = {
1689
1689
  persistentNotes: { label: "Persistent notes", maxLength: 1200 }
1690
1690
  };
1691
1691
  var PROFILE_PROTECTED_SHORT_FIELDS = ["userPreferredName", "assistantPreferredName", "preferredLanguage", "reasoningLanguage", "defaultLocation", "homeCity", "currentCity"];
1692
+ var PROFILE_MAINTAINABLE_FIELDS = Object.keys(PROFILE_FIELDS).filter((field) => !PROFILE_PROTECTED_SHORT_FIELDS.includes(field));
1692
1693
  var PROFILE_TOTAL_MAX_LENGTH = 6e3;
1693
1694
  var PROFILE_MAINTENANCE_INTERVAL_MS = 24 * 60 * 60 * 1e3;
1694
1695
  var PROFILE_MAINTENANCE_TOTAL_THRESHOLD = 4800;
@@ -1714,8 +1715,9 @@ function validateProfile(profile) {
1714
1715
  function profileMaintenanceDue(profile, timeBasisAt, now = Date.now()) {
1715
1716
  const lengths = Object.keys(PROFILE_FIELDS).map((field) => ({ field, length: profileLength(profile[field]) }));
1716
1717
  const total = lengths.reduce((sum, item) => sum + item.length, 0);
1717
- if (total === 0) return false;
1718
- return timeBasisAt !== null && now - Date.parse(timeBasisAt) >= PROFILE_MAINTENANCE_INTERVAL_MS || total >= PROFILE_MAINTENANCE_TOTAL_THRESHOLD || lengths.some(({ field, length }) => length >= PROFILE_FIELDS[field].maxLength * 0.8);
1718
+ const maintainableLengths = lengths.filter(({ field }) => PROFILE_MAINTAINABLE_FIELDS.includes(field));
1719
+ if (!maintainableLengths.some(({ length }) => length > 0)) return false;
1720
+ return timeBasisAt !== null && now - Date.parse(timeBasisAt) >= PROFILE_MAINTENANCE_INTERVAL_MS || total >= PROFILE_MAINTENANCE_TOTAL_THRESHOLD || maintainableLengths.some(({ field, length }) => length >= PROFILE_FIELDS[field].maxLength * 0.8);
1719
1721
  }
1720
1722
  function renderPersistentProfile(profile) {
1721
1723
  const lines = Object.keys(PROFILE_FIELDS).filter((field) => profile[field].length > 0).map((field) => `${PROFILE_FIELDS[field].label}: ${profile[field]}`);
@@ -4279,7 +4281,9 @@ var SqliteStorage = class _SqliteStorage {
4279
4281
  if (failed?.input_json === JSON.stringify(profile) && now < Date.parse(failed.next_retry_at)) return false;
4280
4282
  const state = this.getProfileMaintenanceState();
4281
4283
  if (!profileMaintenanceDue(profile, state?.lastSucceededAt ?? this.getProfileMaintenanceStartedAt(), now)) return false;
4282
- return !state || now - Date.parse(state.lastSucceededAt) >= 24 * 60 * 60 * 1e3 || state.inputJson !== JSON.stringify(profile);
4284
+ if (!state) return true;
4285
+ const maintained = JSON.parse(state.inputJson);
4286
+ return PROFILE_MAINTAINABLE_FIELDS.some((field) => maintained[field] !== profile[field]);
4283
4287
  }
4284
4288
  writeProfileField(field, oldValue, newValue, source, sourceMessageId, now = (/* @__PURE__ */ new Date()).toISOString()) {
4285
4289
  this.database.prepare("INSERT INTO persistent_profile (field, value) VALUES (?, ?) ON CONFLICT (field) DO UPDATE SET value = excluded.value").run(field, newValue);
@@ -5497,6 +5501,7 @@ function agentEventCandidate(content, category, now, threadId) {
5497
5501
  };
5498
5502
  }
5499
5503
  var DERIVATION_BACKOFF_MS = 1e3;
5504
+ var GRAPH_PROJECTION_BATCH_SIZE = 8;
5500
5505
  function restrictExtractionRelations(temporal, allowedIds) {
5501
5506
  const result = { ...temporal };
5502
5507
  if (typeof result.sameEventId !== "string" || !allowedIds.has(result.sameEventId)) {
@@ -6665,6 +6670,18 @@ var StrataGate = class _StrataGate {
6665
6670
  return this.commitMutation(() => {
6666
6671
  const job = [...this.graphProjectionJobs.values()].filter(eligible).sort((left, right) => Number(left.status !== "pending") - Number(right.status !== "pending") || right.priority - left.priority || left.createdAt.localeCompare(right.createdAt))[0];
6667
6672
  if (!job) return null;
6673
+ const sourceEventIds = job.sourceEventIds;
6674
+ for (let index = GRAPH_PROJECTION_BATCH_SIZE; index < sourceEventIds.length; index += GRAPH_PROJECTION_BATCH_SIZE) {
6675
+ const id = this.graphIdFactory("gproj");
6676
+ this.graphProjectionJobs.set(id, {
6677
+ ...job,
6678
+ id,
6679
+ sourceEventIds: sourceEventIds.slice(index, index + GRAPH_PROJECTION_BATCH_SIZE),
6680
+ nodeIds: [],
6681
+ edgeIds: []
6682
+ });
6683
+ }
6684
+ job.sourceEventIds = sourceEventIds.slice(0, GRAPH_PROJECTION_BATCH_SIZE);
6668
6685
  const events = job.sourceEventIds.flatMap((id) => {
6669
6686
  const event = this.findEvent(id);
6670
6687
  return event ? [event] : [];
@@ -7550,30 +7567,30 @@ var StrataGate = class _StrataGate {
7550
7567
  return job;
7551
7568
  }
7552
7569
  queueGraphProjection(sourceEventIds, priority) {
7553
- if (!this.graphProjector) return null;
7554
- const completed = new Set([...this.graphProjectionJobs.values()].filter((job2) => job2.projectorVersion === KNOWLEDGE_GRAPH_PROJECTOR_VERSION && job2.status === "completed").flatMap((job2) => job2.sourceEventIds));
7555
- const queued = new Set([...this.graphProjectionJobs.values()].filter((job2) => job2.projectorVersion === KNOWLEDGE_GRAPH_PROJECTOR_VERSION && job2.status !== "completed").flatMap((job2) => job2.sourceEventIds));
7570
+ if (!this.graphProjector) return;
7571
+ const completed = new Set([...this.graphProjectionJobs.values()].filter((job) => job.projectorVersion === KNOWLEDGE_GRAPH_PROJECTOR_VERSION && job.status === "completed").flatMap((job) => job.sourceEventIds));
7572
+ const queued = new Set([...this.graphProjectionJobs.values()].filter((job) => job.projectorVersion === KNOWLEDGE_GRAPH_PROJECTOR_VERSION && job.status !== "completed").flatMap((job) => job.sourceEventIds));
7556
7573
  const ids2 = [...new Set(sourceEventIds.filter((id) => this.findEvent(id) && !completed.has(id) && !queued.has(id)))];
7557
- if (ids2.length === 0) return null;
7558
7574
  const now = toUtc8Iso(this.now());
7559
- const job = {
7560
- id: this.graphIdFactory("gproj"),
7561
- sourceEventIds: ids2,
7562
- projectorVersion: KNOWLEDGE_GRAPH_PROJECTOR_VERSION,
7563
- status: "pending",
7564
- attempts: 0,
7565
- priority,
7566
- nodeIds: [],
7567
- edgeIds: [],
7568
- nameProvenanceRecoveryVersion: 1,
7569
- reason: null,
7570
- lastError: null,
7571
- nextRetryAt: null,
7572
- createdAt: now,
7573
- updatedAt: now
7574
- };
7575
- this.graphProjectionJobs.set(job.id, job);
7576
- return job;
7575
+ for (let index = 0; index < ids2.length; index += GRAPH_PROJECTION_BATCH_SIZE) {
7576
+ const job = {
7577
+ id: this.graphIdFactory("gproj"),
7578
+ sourceEventIds: ids2.slice(index, index + GRAPH_PROJECTION_BATCH_SIZE),
7579
+ projectorVersion: KNOWLEDGE_GRAPH_PROJECTOR_VERSION,
7580
+ status: "pending",
7581
+ attempts: 0,
7582
+ priority,
7583
+ nodeIds: [],
7584
+ edgeIds: [],
7585
+ nameProvenanceRecoveryVersion: 1,
7586
+ reason: null,
7587
+ lastError: null,
7588
+ nextRetryAt: null,
7589
+ createdAt: now,
7590
+ updatedAt: now
7591
+ };
7592
+ this.graphProjectionJobs.set(job.id, job);
7593
+ }
7577
7594
  }
7578
7595
  recoverGraphNameProvenanceFailures() {
7579
7596
  for (const job of this.graphProjectionJobs.values()) {
@@ -7591,8 +7608,8 @@ var StrataGate = class _StrataGate {
7591
7608
  const score = (event) => (event.status === "active" ? 1e4 : 0) + event.weight.mentionCount * 100 + (event.scope === "project" ? 500 : 0) + (Date.parse(event.temporal.happenedStart ?? event.temporal.mentionedAt ?? event.updatedAt) || 0) / 1e12;
7592
7609
  return score(right) - score(left);
7593
7610
  });
7594
- for (let index = 0; index < candidates.length; index += 8) {
7595
- this.queueGraphProjection(candidates.slice(index, index + 8).map(({ id }) => id), candidates.length - index);
7611
+ for (let index = 0; index < candidates.length; index += GRAPH_PROJECTION_BATCH_SIZE) {
7612
+ this.queueGraphProjection(candidates.slice(index, index + GRAPH_PROJECTION_BATCH_SIZE).map(({ id }) => id), candidates.length - index);
7596
7613
  }
7597
7614
  }
7598
7615
  queueElementProjection(sourceEventIds) {
@@ -9052,6 +9069,7 @@ function parseTopicProjection(value, context) {
9052
9069
  return { topics };
9053
9070
  }
9054
9071
  var TOPIC_OUTPUT_TOKEN_BUDGET = 32768;
9072
+ var GRAPH_OUTPUT_TOKEN_BUDGET = 32768;
9055
9073
  var DshModelBridge = class {
9056
9074
  constructor(ctx, config, liveStructuredReasoningEffort) {
9057
9075
  this.ctx = ctx;
@@ -9387,6 +9405,7 @@ Use project scope for repository decisions, user scope for stable preferences/id
9387
9405
  const routeKey = `${baseRoute.provider}\0${baseRoute.model}`;
9388
9406
  let useOff = await this.shouldUseOff(baseRoute);
9389
9407
  const isTopic = kind === "topicProjector";
9408
+ const isGraph = kind === "graphProjector";
9390
9409
  const topicDiagnostics = {
9391
9410
  ...topicMetadata,
9392
9411
  requestedOutputTokens: TOPIC_OUTPUT_TOKEN_BUDGET,
@@ -9413,7 +9432,7 @@ Use project scope for repository decisions, user scope for stable preferences/id
9413
9432
  }
9414
9433
  }
9415
9434
  const message = createUserMessage({
9416
- content: [{ type: "text", text: JSON.stringify(payload) }],
9435
+ content: [{ type: "text", text: JSON.stringify(isGraph ? { ...object(payload), outputTokenBudget: GRAPH_OUTPUT_TOKEN_BUDGET } : payload) }],
9417
9436
  source: dshMessageSource()
9418
9437
  });
9419
9438
  const assembler = new BlockAssembler();
@@ -9433,7 +9452,7 @@ ${JSON_RETRY_INSTRUCTION}${graphRetryFeedback}${topicRetryFeedback}`,
9433
9452
  type: "function",
9434
9453
  function: { name: STRUCTURED_TOOLS[kind].name }
9435
9454
  },
9436
- maxTokens: kind === "dreamingStep" ? TOPIC_OUTPUT_TOKEN_BUDGET : kind === "profileMaintenance" ? Math.max(this.config.maxOutputTokens, Math.min(12e3, 512 + 2 * Array.from(JSON.stringify(payload)).length)) : isTopic ? TOPIC_OUTPUT_TOKEN_BUDGET : this.config.maxOutputTokens,
9455
+ maxTokens: kind === "dreamingStep" ? TOPIC_OUTPUT_TOKEN_BUDGET : kind === "profileMaintenance" ? Math.max(this.config.maxOutputTokens, Math.min(12e3, 512 + 2 * Array.from(JSON.stringify(payload)).length)) : isTopic ? TOPIC_OUTPUT_TOKEN_BUDGET : isGraph ? GRAPH_OUTPUT_TOKEN_BUDGET : this.config.maxOutputTokens,
9437
9456
  sessionId: execution.sessionId,
9438
9457
  purpose: "compaction"
9439
9458
  };
@@ -9445,6 +9464,18 @@ ${JSON_RETRY_INSTRUCTION}${graphRetryFeedback}${topicRetryFeedback}`,
9445
9464
  request.maxTokens = Math.min(TOPIC_OUTPUT_TOKEN_BUDGET, Math.floor(window - input - 1024));
9446
9465
  }
9447
9466
  }
9467
+ if (isGraph) {
9468
+ const input = estimateTokens(JSON.stringify({ system: request.system, tools: request.tools, messages: request.messages }));
9469
+ const window = this.contextWindows.get(routeKey);
9470
+ if (window !== void 0) {
9471
+ if (window - input - 1024 < 256) throw new Error("Graph input exceeds model context capacity; reduce the source batch");
9472
+ request.maxTokens = Math.min(GRAPH_OUTPUT_TOKEN_BUDGET, Math.floor(window - input - 1024));
9473
+ }
9474
+ request.messages = [{ ...message, content: [{ type: "text", text: JSON.stringify({
9475
+ ...object(payload),
9476
+ outputTokenBudget: request.maxTokens
9477
+ }) }] }];
9478
+ }
9448
9479
  if (isTopic) {
9449
9480
  const estimateInput = () => estimateTokens(JSON.stringify({ system: request.system, tools: request.tools, messages: request.messages }));
9450
9481
  let inputTokens = estimateInput();
@@ -9522,6 +9553,9 @@ ${JSON_RETRY_INSTRUCTION}${graphRetryFeedback}${topicRetryFeedback}`,
9522
9553
  [finish=${finish.kind}; toolCalls=${calls.length}]`;
9523
9554
  lastResponse = responseForError;
9524
9555
  try {
9556
+ if (isGraph && finish.kind === "max-tokens") {
9557
+ throw new ModelJsonResponseError("StrataGate Graph output token limit reached", { response: responseForError });
9558
+ }
9525
9559
  const expectedTool = STRUCTURED_TOOLS[kind].name;
9526
9560
  let parsed;
9527
9561
  if (calls.length !== 1 || calls[0]?.name !== expectedTool) {