@cortexkit/pi-magic-context 0.49.1 → 0.49.2

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.
Files changed (2) hide show
  1. package/dist/index.js +522 -44
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3413,7 +3413,7 @@ function startHostStallProfilerSwitch() {
3413
3413
  // package.json
3414
3414
  var package_default = {
3415
3415
  name: "@cortexkit/pi-magic-context",
3416
- version: "0.49.1",
3416
+ version: "0.49.2",
3417
3417
  type: "module",
3418
3418
  description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
3419
3419
  main: "dist/index.js",
@@ -31617,6 +31617,22 @@ function isOmpUnmanagedCaptureRequest(payload) {
31617
31617
  return last?.role === "user" && firstText(last.content, request.textType)?.startsWith(CAPTURE_PREFIX) === true;
31618
31618
  }
31619
31619
 
31620
+ // src/pi-dispatch-google.ts
31621
+ function piGoogleConversation(payload) {
31622
+ if (!payload || typeof payload !== "object")
31623
+ return;
31624
+ const body = payload;
31625
+ if (body.messages !== undefined || body.input !== undefined)
31626
+ return;
31627
+ if (Array.isArray(body.contents))
31628
+ return body;
31629
+ const request = body.request;
31630
+ if (!request || typeof request !== "object")
31631
+ return;
31632
+ const conversation = request;
31633
+ return Array.isArray(conversation.contents) ? conversation : undefined;
31634
+ }
31635
+
31620
31636
  // src/pi-dispatch-identity.ts
31621
31637
  var MAX_NODES = 1e5;
31622
31638
  var MAX_STRING_UNITS = 32 * 1024 * 1024;
@@ -31639,8 +31655,16 @@ function piConversationFields(payload) {
31639
31655
  conversation: body.conversation,
31640
31656
  prompt: body.prompt
31641
31657
  };
31642
- } else
31643
- return;
31658
+ } else {
31659
+ const google = piGoogleConversation(payload);
31660
+ if (!google)
31661
+ return;
31662
+ conversation = {
31663
+ contents: google.contents,
31664
+ systemInstruction: google.systemInstruction,
31665
+ configSystemInstruction: google.config?.systemInstruction
31666
+ };
31667
+ }
31644
31668
  const fields = [];
31645
31669
  const seen = new WeakSet;
31646
31670
  let nodes = 0;
@@ -31716,34 +31740,281 @@ function piHasManagedSignature(payload, signature) {
31716
31740
  if (!signature || !payload || typeof payload !== "object")
31717
31741
  return false;
31718
31742
  const body = payload;
31743
+ const google = piGoogleConversation(payload);
31744
+ const nativeText = !!google || body.inferenceConfig !== undefined;
31719
31745
  if (typeof body.input === "string" && body.messages === undefined)
31720
31746
  return body.input.slice(0, 4096).includes(signature);
31721
- const messages = Array.isArray(body.messages) ? body.messages : Array.isArray(body.input) ? body.input : undefined;
31747
+ const messages = Array.isArray(body.messages) ? body.messages : Array.isArray(body.input) ? body.input : google?.contents;
31722
31748
  if (!messages)
31723
31749
  return false;
31724
31750
  for (const message of messages.slice(0, 8)) {
31725
31751
  if (!message || typeof message !== "object")
31726
31752
  continue;
31727
- const content = message.content;
31753
+ const content = google ? message.parts : message.content;
31728
31754
  if (typeof content === "string" && content.slice(0, 4096).includes(signature))
31729
31755
  return true;
31730
31756
  if (!Array.isArray(content))
31731
31757
  continue;
31732
31758
  for (const block of content.slice(0, 32)) {
31733
- if (block && ["text", "input_text", "output_text"].includes(block.type) && typeof block.text === "string" && block.text.slice(0, 4096).includes(signature))
31759
+ if (block && (["text", "input_text", "output_text"].includes(block.type) || nativeText && block.type === undefined) && typeof block.text === "string" && block.text.slice(0, 4096).includes(signature))
31734
31760
  return true;
31735
31761
  }
31736
31762
  }
31737
31763
  return false;
31738
31764
  }
31739
31765
 
31766
+ // src/pi-dispatch-chat-history.ts
31767
+ var MAX_EXACT_UNITS = 32 * 1024 * 1024;
31768
+ var IMAGE_CAPTION = "Attached image(s) from tool result:";
31769
+ function object(value) {
31770
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
31771
+ }
31772
+ function omitsAssistant(message, model, compat) {
31773
+ if (!Array.isArray(message.content))
31774
+ return false;
31775
+ let thinking = false;
31776
+ let hasTextBlock = false;
31777
+ for (const value of message.content) {
31778
+ const block = object(value);
31779
+ if (!block)
31780
+ return false;
31781
+ if (block.type === "text") {
31782
+ hasTextBlock = true;
31783
+ if (typeof block.text !== "string" || block.text.trim())
31784
+ return false;
31785
+ } else if (block.type === "thinking") {
31786
+ if (typeof block.thinking !== "string")
31787
+ return false;
31788
+ thinking ||= block.thinking.trim().length > 0;
31789
+ } else
31790
+ return false;
31791
+ }
31792
+ if (!hasTextBlock && ["length", "error", "aborted"].includes(String(message.stopReason)))
31793
+ return true;
31794
+ if (compat.requiresReasoningContentForAllAssistantTurns === true)
31795
+ return false;
31796
+ if (!thinking)
31797
+ return true;
31798
+ return message.api === model.api && message.provider === model.provider && message.model === model.id && compat.requiresThinkingAsText !== true && compat.requiresReasoningContentForToolCalls !== true && compat.replayReasoningContent !== true && compat.mistralReasoningContentParts !== true && compat.thinkingFormat !== "zai";
31799
+ }
31800
+ function piChatHistoryPlan(messages, model) {
31801
+ if (model?.api !== "openai-completions")
31802
+ return;
31803
+ const compat = object(model.compat) ?? {};
31804
+ const calls = new Set;
31805
+ for (const value of messages) {
31806
+ const message = object(value);
31807
+ if (message?.role !== "assistant" || !Array.isArray(message.content))
31808
+ continue;
31809
+ for (const value of message.content) {
31810
+ const block = object(value);
31811
+ if (block?.type === "toolCall" && typeof block.id === "string")
31812
+ calls.add(block.id);
31813
+ }
31814
+ }
31815
+ const transformed = [];
31816
+ let pending = new Set;
31817
+ let exactUnits = 0;
31818
+ for (let index = 0;index < messages.length; index++) {
31819
+ const message = object(messages[index]);
31820
+ if (!message)
31821
+ return;
31822
+ if ((message.role === "bashExecution" || message.role === "pythonExecution") && message.excludeFromContext === true)
31823
+ continue;
31824
+ if (message.role === "assistant" || message.role === "user" || message.role === "developer")
31825
+ pending = new Set;
31826
+ if (message.role === "assistant") {
31827
+ if (omitsAssistant(message, model, compat))
31828
+ continue;
31829
+ if (Array.isArray(message.content))
31830
+ for (const value of message.content) {
31831
+ const block = object(value);
31832
+ if (block?.type === "toolCall" && typeof block.id === "string")
31833
+ pending.add(block.id);
31834
+ }
31835
+ }
31836
+ if (message.role === "toolResult" && typeof message.toolCallId === "string") {
31837
+ pending.delete(message.toolCallId);
31838
+ if (!calls.has(message.toolCallId)) {
31839
+ if (pending.size || typeof message.toolName !== "string" || !Array.isArray(message.content))
31840
+ return;
31841
+ const parts = [];
31842
+ for (const value of message.content) {
31843
+ const part = object(value);
31844
+ if (part?.type === "text" && typeof part.text === "string" && part.text.trim())
31845
+ parts.push(part.text);
31846
+ }
31847
+ if (!parts.length)
31848
+ return;
31849
+ const error = message.isError ? ' is-error="true"' : "";
31850
+ const template = `<stale-tool-result tool="${message.toolName}" id="${message.toolCallId}"${error}>
31851
+ ${parts.join(`
31852
+ `)}
31853
+ </stale-tool-result>`;
31854
+ if (exactUnits + template.length > MAX_EXACT_UNITS)
31855
+ return;
31856
+ const text = new TextDecoder().decode(new TextEncoder().encode(template));
31857
+ exactUnits += text.length;
31858
+ if (exactUnits > MAX_EXACT_UNITS)
31859
+ return;
31860
+ transformed.push({ kind: "note", text });
31861
+ continue;
31862
+ }
31863
+ }
31864
+ transformed.push({ kind: "source", index });
31865
+ }
31866
+ const steps = [];
31867
+ let images = [];
31868
+ const flushImages = () => {
31869
+ if (images.length) {
31870
+ steps.push({ kind: "images", urls: images });
31871
+ images = [];
31872
+ }
31873
+ };
31874
+ const vision = model.input?.includes("image") === true && compat.stripImageInput !== true;
31875
+ for (const step of transformed) {
31876
+ const message = step.kind === "source" ? object(messages[step.index]) : undefined;
31877
+ if (message?.role !== "toolResult")
31878
+ flushImages();
31879
+ steps.push(step);
31880
+ if (message?.role !== "toolResult" || !vision || !Array.isArray(message.content))
31881
+ continue;
31882
+ for (const value of message.content) {
31883
+ const block = object(value);
31884
+ if (block?.type !== "image")
31885
+ continue;
31886
+ if (compat.requiresAssistantAfterToolResult === true)
31887
+ return;
31888
+ let url;
31889
+ if (typeof block.url === "string")
31890
+ url = block.url;
31891
+ else if (typeof block.data === "string" && typeof block.mimeType === "string")
31892
+ url = `data:${block.mimeType};base64,${block.data}`;
31893
+ else
31894
+ return;
31895
+ exactUnits += url.length;
31896
+ if (exactUnits > MAX_EXACT_UNITS)
31897
+ return;
31898
+ images.push(url);
31899
+ }
31900
+ }
31901
+ flushImages();
31902
+ return steps;
31903
+ }
31904
+ function piMatchesChatImages(content, urls) {
31905
+ if (!Array.isArray(content) || content.length !== urls.length + 1)
31906
+ return false;
31907
+ const caption = object(content[0]);
31908
+ if (caption?.type !== "text" || caption.text !== IMAGE_CAPTION || Object.keys(caption).length !== 2)
31909
+ return false;
31910
+ for (let i = 0;i < urls.length; i++) {
31911
+ const block = object(content[i + 1]);
31912
+ const image = object(block?.image_url);
31913
+ if (block?.type !== "image_url" || Object.keys(block).length !== 2 || !image || Object.keys(image).length !== 1 || image.url !== urls[i])
31914
+ return false;
31915
+ }
31916
+ return true;
31917
+ }
31918
+
31919
+ // src/pi-dispatch-responses-history.ts
31920
+ var MAX_TEXT_UNITS = 32 * 1024 * 1024;
31921
+ function object2(value) {
31922
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
31923
+ }
31924
+ function wellFormed(text) {
31925
+ return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "�");
31926
+ }
31927
+ function textIdentity(text, phase) {
31928
+ return JSON.stringify([
31929
+ text,
31930
+ phase === "commentary" || phase === "final_answer" ? phase : null
31931
+ ]);
31932
+ }
31933
+ function signaturePhase(block) {
31934
+ try {
31935
+ if (typeof block.textSignature === "string") {
31936
+ const signature = object2(JSON.parse(block.textSignature));
31937
+ if (signature?.v === 1 && typeof signature.id === "string")
31938
+ return signature.phase;
31939
+ }
31940
+ } catch {}
31941
+ return;
31942
+ }
31943
+ function piResponsesAssistantTexts(value, model) {
31944
+ const message = object2(value);
31945
+ if (!message || !Array.isArray(message.content))
31946
+ return;
31947
+ const texts = [];
31948
+ const blocks = [];
31949
+ let units = 0;
31950
+ for (const value of message.content) {
31951
+ const block = object2(value);
31952
+ if (block?.type === "toolCall")
31953
+ continue;
31954
+ if (block?.type !== "text" || typeof block.text !== "string")
31955
+ return;
31956
+ units += block.text.length;
31957
+ if (units > MAX_TEXT_UNITS)
31958
+ return;
31959
+ const sameModel = message.api === model?.api && message.model === model?.id && message.provider === model?.provider;
31960
+ texts.push(textIdentity(wellFormed(block.text), sameModel ? signaturePhase(block) : undefined));
31961
+ blocks.push(block);
31962
+ }
31963
+ const payload = object2(message.providerPayload);
31964
+ if (message.api !== model?.api || typeof model?.id !== "string" || typeof model?.provider !== "string" || message.model !== model?.id || (payload?.provider ?? message.provider) !== model?.provider || payload?.type !== "openaiResponsesHistory" || payload.dt !== true || !Array.isArray(payload.items) || message.content.length !== blocks.length)
31965
+ return texts;
31966
+ const replay = [];
31967
+ for (const value of payload.items) {
31968
+ const item = object2(value);
31969
+ if (item?.type !== "message" || item.role !== "assistant" || !Array.isArray(item.content))
31970
+ return texts;
31971
+ for (const value of item.content) {
31972
+ const part = object2(value);
31973
+ const block = blocks[replay.length];
31974
+ if (!block || part?.type !== "output_text" || typeof part.text !== "string")
31975
+ return texts;
31976
+ let signature;
31977
+ try {
31978
+ if (typeof block.textSignature === "string")
31979
+ signature = object2(JSON.parse(block.textSignature));
31980
+ } catch {
31981
+ return texts;
31982
+ }
31983
+ if (signature?.v !== 1 || typeof signature.id !== "string" || item.id !== signature.id || item.phase !== signature.phase || part.text !== block.text.replace(/^§\d+§ /u, ""))
31984
+ return texts;
31985
+ replay.push(textIdentity(wellFormed(part.text), item.phase));
31986
+ }
31987
+ }
31988
+ return replay.length === texts.length ? replay : texts;
31989
+ }
31990
+ function piResponsesWireTexts(value, phase) {
31991
+ if (phase !== undefined && phase !== null && phase !== "commentary" && phase !== "final_answer")
31992
+ return;
31993
+ if (typeof value === "string")
31994
+ return [textIdentity(value, phase)];
31995
+ if (!Array.isArray(value))
31996
+ return;
31997
+ const texts = [];
31998
+ let units = 0;
31999
+ for (const partValue of value) {
32000
+ const part = object2(partValue);
32001
+ if (part?.type !== "output_text" || typeof part.text !== "string")
32002
+ return;
32003
+ units += part.text.length;
32004
+ if (units > MAX_TEXT_UNITS)
32005
+ return;
32006
+ texts.push(textIdentity(part.text, phase));
32007
+ }
32008
+ return texts;
32009
+ }
32010
+
31740
32011
  // src/pi-dispatch-structure.ts
31741
32012
  var MAX_MESSAGES = 1e5;
31742
- function object(value) {
32013
+ function object3(value) {
31743
32014
  return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
31744
32015
  }
31745
32016
  function messageStructure(value) {
31746
- const message = object(value);
32017
+ const message = object3(value);
31747
32018
  if (!message)
31748
32019
  return;
31749
32020
  const role = [
@@ -31767,35 +32038,103 @@ function messageStructure(value) {
31767
32038
  }
31768
32039
  if (role === "assistant" && Array.isArray(message.content)) {
31769
32040
  for (const value of message.content) {
31770
- const block = object(value);
32041
+ const block = object3(value);
31771
32042
  if (block?.type !== "toolCall" && block?.type !== "tool_use")
31772
32043
  continue;
31773
32044
  if (typeof block.id !== "string")
31774
32045
  return;
31775
32046
  row.calls.push(block.id);
32047
+ row.callNames ??= [];
32048
+ row.callNames.push(typeof block.name === "string" ? block.name : "");
31776
32049
  }
31777
32050
  }
31778
32051
  return row;
31779
32052
  }
31780
- function piPreparedStructure(messages) {
32053
+ function piPreparedStructure(messages, model) {
31781
32054
  if (!messages.length || messages.length > MAX_MESSAGES)
31782
32055
  return;
31783
32056
  const rows = [];
31784
- for (const message of messages) {
31785
- const source = object(message);
32057
+ const toolNames = new Map;
32058
+ const byIndex = new Map;
32059
+ for (let index = 0;index < messages.length; index++) {
32060
+ const message = messages[index];
32061
+ const source = object3(message);
32062
+ if (rows.length === 0 && (source?.role === "system" || source?.role === "developer"))
32063
+ continue;
31786
32064
  if ((source?.role === "bashExecution" || source?.role === "pythonExecution") && source.excludeFromContext === true)
31787
32065
  continue;
31788
32066
  const row = messageStructure(message);
31789
32067
  if (!row)
31790
32068
  return;
32069
+ row.calls.forEach((id, index) => {
32070
+ toolNames.set(id, row.callNames?.[index] ?? "");
32071
+ });
32072
+ if (row.results.length)
32073
+ row.resultNames = row.results.map((id) => toolNames.get(id) ?? "");
31791
32074
  rows.push(row);
32075
+ byIndex.set(index, row);
32076
+ }
32077
+ const responsesApi = [
32078
+ "openai-responses",
32079
+ "azure-openai-responses",
32080
+ "openai-codex-responses"
32081
+ ].includes(model?.api ?? "");
32082
+ let responsesMessages = responsesApi ? [] : undefined;
32083
+ if (responsesMessages) {
32084
+ for (const [index, row] of byIndex) {
32085
+ if (row.role !== "assistant") {
32086
+ responsesMessages.push(row);
32087
+ continue;
32088
+ }
32089
+ const texts = piResponsesAssistantTexts(messages[index], model);
32090
+ if (!texts) {
32091
+ responsesMessages = undefined;
32092
+ break;
32093
+ }
32094
+ if (!texts.length && !row.calls.length)
32095
+ continue;
32096
+ const previous = responsesMessages.at(-1);
32097
+ if (previous?.role === "assistant") {
32098
+ previous.calls.push(...row.calls);
32099
+ previous.responseTexts?.push(...texts);
32100
+ } else
32101
+ responsesMessages.push({
32102
+ ...row,
32103
+ calls: [...row.calls],
32104
+ responseTexts: [...texts]
32105
+ });
32106
+ }
31792
32107
  }
31793
- return { messages: rows };
32108
+ const plan = piChatHistoryPlan(messages, model);
32109
+ const chatMessages = plan?.flatMap((step) => {
32110
+ if (step.kind === "source") {
32111
+ const row = byIndex.get(step.index);
32112
+ return row ? [row] : [];
32113
+ }
32114
+ return [
32115
+ {
32116
+ role: "user",
32117
+ calls: [],
32118
+ results: [],
32119
+ ...step.kind === "note" ? { exactText: step.text } : { exactImages: step.urls }
32120
+ }
32121
+ ];
32122
+ });
32123
+ return {
32124
+ messages: rows,
32125
+ ...chatMessages ? { chatMessages } : {},
32126
+ ...responsesMessages ? { responsesMessages } : {},
32127
+ ...model?.api ? { api: model.api } : {}
32128
+ };
31794
32129
  }
31795
- function payloadStructure(payload) {
31796
- const body = object(payload);
32130
+ function payloadStructure(payload, ollama = false, responsesItems = false) {
32131
+ const body = object3(payload);
31797
32132
  if (!body)
31798
32133
  return;
32134
+ const google = piGoogleConversation(payload);
32135
+ if (google)
32136
+ return googleStructure(google.contents);
32137
+ const bedrock = body.inferenceConfig !== undefined;
31799
32138
  if (body.messages === undefined && typeof body.input === "string")
31800
32139
  return [{ role: "user", calls: [], results: [] }];
31801
32140
  const responses = body.messages === undefined && Array.isArray(body.input);
@@ -31804,10 +32143,10 @@ function payloadStructure(payload) {
31804
32143
  return;
31805
32144
  const rows = [];
31806
32145
  for (const value of messages) {
31807
- const message = object(value);
32146
+ const message = object3(value);
31808
32147
  if (!message)
31809
32148
  return;
31810
- if (!responses && rows.length === 0 && (message.role === "system" || message.role === "developer"))
32149
+ if (rows.length === 0 && (message.role === "system" || message.role === "developer"))
31811
32150
  continue;
31812
32151
  if (responses && message.type === "reasoning")
31813
32152
  continue;
@@ -31816,7 +32155,12 @@ function payloadStructure(payload) {
31816
32155
  return;
31817
32156
  let assistant = rows.at(-1);
31818
32157
  if (assistant?.role !== "assistant") {
31819
- assistant = { role: "assistant", calls: [], results: [] };
32158
+ assistant = {
32159
+ role: "assistant",
32160
+ calls: [],
32161
+ results: [],
32162
+ ...responsesItems ? { responseTexts: [] } : {}
32163
+ };
31820
32164
  rows.push(assistant);
31821
32165
  }
31822
32166
  assistant.calls.push(message.call_id);
@@ -31833,6 +32177,16 @@ function payloadStructure(payload) {
31833
32177
  continue;
31834
32178
  }
31835
32179
  if (message.role === "tool") {
32180
+ if (message.tool_call_id === undefined && ollama && typeof message.tool_name === "string") {
32181
+ rows.push({
32182
+ role: "toolResult",
32183
+ calls: [],
32184
+ results: [""],
32185
+ resultNames: [message.tool_name],
32186
+ idlessResults: [true]
32187
+ });
32188
+ continue;
32189
+ }
31836
32190
  if (typeof message.tool_call_id !== "string")
31837
32191
  return;
31838
32192
  rows.push({
@@ -31843,15 +32197,16 @@ function payloadStructure(payload) {
31843
32197
  continue;
31844
32198
  }
31845
32199
  if (message.role === "user" && Array.isArray(message.content)) {
31846
- const results = message.content.filter((block) => object(block)?.type === "tool_result");
32200
+ const results = message.content.filter((block) => object3(block)?.type === "tool_result" || bedrock && object3(block)?.toolResult);
31847
32201
  if (results.length) {
31848
32202
  for (const block of results) {
31849
- if (typeof block.tool_use_id !== "string")
32203
+ const id = bedrock ? block.toolResult?.toolUseId : block.tool_use_id;
32204
+ if (typeof id !== "string")
31850
32205
  return;
31851
32206
  rows.push({
31852
32207
  role: "toolResult",
31853
32208
  calls: [],
31854
- results: [block.tool_use_id]
32209
+ results: [id]
31855
32210
  });
31856
32211
  }
31857
32212
  continue;
@@ -31860,20 +32215,107 @@ function payloadStructure(payload) {
31860
32215
  const row = messageStructure(message);
31861
32216
  if (!row)
31862
32217
  return;
32218
+ row.wireContent = message.content;
32219
+ if (responses && responsesItems && row.role === "assistant") {
32220
+ const texts = piResponsesWireTexts(message.content, message.phase);
32221
+ if (!texts)
32222
+ return;
32223
+ row.responseTexts = [...texts];
32224
+ }
32225
+ row.wireRole = message.role;
32226
+ if (bedrock && row.role === "assistant" && Array.isArray(message.content)) {
32227
+ for (const block of message.content) {
32228
+ if (!block?.toolUse)
32229
+ continue;
32230
+ if (typeof block.toolUse.toolUseId !== "string")
32231
+ return;
32232
+ row.calls.push(block.toolUse.toolUseId);
32233
+ }
32234
+ }
31863
32235
  if (Array.isArray(message.tool_calls)) {
31864
32236
  for (const call of message.tool_calls) {
31865
- if (typeof call?.id !== "string")
32237
+ const source = object3(call);
32238
+ if (!source)
31866
32239
  return;
31867
- row.calls.push(call.id);
32240
+ if (source.id === undefined && ollama) {
32241
+ const fn = object3(source.function);
32242
+ if (typeof fn?.name !== "string")
32243
+ return;
32244
+ row.calls.push("");
32245
+ row.callNames ??= [];
32246
+ row.callNames.push(fn.name);
32247
+ row.idlessCalls ??= [];
32248
+ row.idlessCalls.push(true);
32249
+ } else {
32250
+ if (typeof source.id !== "string")
32251
+ return;
32252
+ row.calls.push(source.id);
32253
+ if (ollama) {
32254
+ row.callNames ??= [];
32255
+ row.callNames.push("");
32256
+ row.idlessCalls ??= [];
32257
+ row.idlessCalls.push(false);
32258
+ }
32259
+ }
31868
32260
  }
31869
32261
  }
31870
32262
  if (responses && row.role === "assistant" && rows.at(-1)?.role === "assistant") {
31871
- rows[rows.length - 1].calls.push(...row.calls);
32263
+ const previous = rows[rows.length - 1];
32264
+ previous.calls.push(...row.calls);
32265
+ if (responsesItems)
32266
+ previous.responseTexts?.push(...row.responseTexts ?? []);
31872
32267
  } else
31873
32268
  rows.push(row);
31874
32269
  }
31875
32270
  return rows;
31876
32271
  }
32272
+ function googleStructure(contents) {
32273
+ if (contents.length > MAX_MESSAGES)
32274
+ return;
32275
+ const rows = [];
32276
+ for (const value of contents) {
32277
+ const message = object3(value);
32278
+ if (!message || !Array.isArray(message.parts))
32279
+ return;
32280
+ if (message.role !== "user" && message.role !== "model")
32281
+ return;
32282
+ const row = {
32283
+ role: message.role === "model" ? "assistant" : "user",
32284
+ calls: [],
32285
+ results: []
32286
+ };
32287
+ const results = [];
32288
+ for (const value of message.parts) {
32289
+ const part = object3(value);
32290
+ if (!part)
32291
+ return;
32292
+ if (part.functionCall) {
32293
+ const call = object3(part.functionCall);
32294
+ if (row.role !== "assistant" || typeof call?.name !== "string" || call.id !== undefined && typeof call.id !== "string")
32295
+ return;
32296
+ row.calls.push(call.id ?? "");
32297
+ row.callNames ??= [];
32298
+ row.callNames.push(call.name);
32299
+ }
32300
+ if (part.functionResponse) {
32301
+ const result = object3(part.functionResponse);
32302
+ if (row.role !== "user" || typeof result?.name !== "string" || result.id !== undefined && typeof result.id !== "string")
32303
+ return;
32304
+ results.push({
32305
+ role: "toolResult",
32306
+ calls: [],
32307
+ results: [result.id ?? ""],
32308
+ resultNames: [result.name]
32309
+ });
32310
+ }
32311
+ }
32312
+ if (results.length)
32313
+ rows.push(...results);
32314
+ else
32315
+ rows.push(row);
32316
+ }
32317
+ return rows;
32318
+ }
31877
32319
  function wireId(id, anthropic, responses) {
31878
32320
  if (anthropic)
31879
32321
  return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
@@ -31883,29 +32325,64 @@ function wireId(id, anthropic, responses) {
31883
32325
  }
31884
32326
  return id;
31885
32327
  }
31886
- function piMatchesPreparedStructure(payload, prepared) {
32328
+ function safeRole(row, readable) {
32329
+ if (!readable)
32330
+ return "unreadable";
32331
+ if (!row)
32332
+ return "missing";
32333
+ return ["user", "assistant", "toolResult"].includes(row.role) ? row.role : "unknown";
32334
+ }
32335
+ function safeCount(value) {
32336
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : "unreadable";
32337
+ }
32338
+ function structureDetail(index, expected, actual, comparison) {
32339
+ const expectedRow = expected?.[index];
32340
+ const actualRow = actual?.[index];
32341
+ return `row=${index} expectedRows=${safeCount(expected?.length)} actualRows=${safeCount(actual?.length)} expectedRole=${safeRole(expectedRow, !!expected)} actualRole=${safeRole(actualRow, !!actual)} expectedCalls=${safeCount(expected ? expectedRow?.calls.length ?? 0 : undefined)} actualCalls=${safeCount(actual ? actualRow?.calls.length ?? 0 : undefined)} expectedResults=${safeCount(expected ? expectedRow?.results.length ?? 0 : undefined)} actualResults=${safeCount(actual ? actualRow?.results.length ?? 0 : undefined)} comparison=${comparison}`;
32342
+ }
32343
+ function piPreparedStructureMismatch(payload, prepared) {
31887
32344
  try {
31888
- const rows = payloadStructure(payload);
31889
- if (!rows || !prepared || rows.length !== prepared.messages.length)
31890
- return false;
31891
- const body = payload;
31892
- const anthropic = typeof body.system === "string" || Array.isArray(body.system);
31893
- const responses = body.messages === undefined && Array.isArray(body.input);
31894
- for (let i = 0;i < rows.length; i++) {
31895
- const expected = prepared.messages[i];
32345
+ const body = object3(payload);
32346
+ const ollama = prepared?.api === "ollama-chat" && !!body && Array.isArray(body.messages) && body.input === undefined && body.system === undefined && body.inferenceConfig === undefined;
32347
+ const responses = body?.messages === undefined && Array.isArray(body?.input);
32348
+ const rows = payloadStructure(payload, ollama, responses && !!prepared?.responsesMessages);
32349
+ const chat = !!body && Array.isArray(body.messages) && body.system === undefined && body.input === undefined && body.inferenceConfig === undefined;
32350
+ const expectedRows = responses && prepared?.responsesMessages ? prepared.responsesMessages : chat && prepared?.chatMessages ? prepared.chatMessages : prepared?.messages;
32351
+ if (!rows || !expectedRows)
32352
+ return structureDetail(0, expectedRows, rows, "count");
32353
+ if (!body)
32354
+ return structureDetail(0, expectedRows, rows, "count");
32355
+ const google = !!piGoogleConversation(payload);
32356
+ const anthropic = google || body.inferenceConfig !== undefined || typeof body.system === "string" || Array.isArray(body.system);
32357
+ for (let i = 0;i < Math.min(rows.length, expectedRows.length); i++) {
32358
+ const expected = expectedRows[i];
31896
32359
  const actual = rows[i];
31897
- if (actual.role !== expected.role || actual.calls.length !== expected.calls.length || actual.results.length !== expected.results.length || actual.timestamp !== undefined && actual.timestamp !== expected.timestamp)
31898
- return false;
32360
+ if (actual.role !== expected.role)
32361
+ return structureDetail(i, expectedRows, rows, "role");
32362
+ if (expected.responseTexts !== undefined && (expected.responseTexts.length !== actual.responseTexts?.length || expected.responseTexts.some((text, index) => text !== actual.responseTexts?.[index])))
32363
+ return structureDetail(i, expectedRows, rows, "content");
32364
+ if (expected.exactText !== undefined || expected.exactImages !== undefined) {
32365
+ if (actual.wireRole !== "user")
32366
+ return structureDetail(i, expectedRows, rows, "role");
32367
+ if (expected.exactText !== undefined && actual.wireContent !== expected.exactText || expected.exactImages !== undefined && !piMatchesChatImages(actual.wireContent, expected.exactImages))
32368
+ return structureDetail(i, expectedRows, rows, "content");
32369
+ }
32370
+ if (actual.calls.length !== expected.calls.length || actual.results.length !== expected.results.length)
32371
+ return structureDetail(i, expectedRows, rows, "count");
32372
+ if (actual.timestamp !== undefined && actual.timestamp !== expected.timestamp)
32373
+ return structureDetail(i, expectedRows, rows, "timestamp");
31899
32374
  for (let j = 0;j < actual.calls.length; j++)
31900
- if (actual.calls[j] !== wireId(expected.calls[j], anthropic, responses))
31901
- return false;
32375
+ if (google && actual.calls[j] === "" || ollama && actual.idlessCalls?.[j] === true ? !expected.callNames?.[j] || actual.callNames?.[j] !== expected.callNames[j] : actual.calls[j] !== wireId(expected.calls[j], anthropic, responses))
32376
+ return structureDetail(i, expectedRows, rows, google && actual.calls[j] === "" || ollama && actual.idlessCalls?.[j] === true ? "name" : "call id");
31902
32377
  for (let j = 0;j < actual.results.length; j++)
31903
- if (actual.results[j] !== wireId(expected.results[j], anthropic, responses))
31904
- return false;
32378
+ if (google && actual.results[j] === "" || ollama && actual.idlessResults?.[j] === true ? !expected.resultNames?.[j] || actual.resultNames?.[j] !== expected.resultNames[j] : actual.results[j] !== wireId(expected.results[j], anthropic, responses))
32379
+ return structureDetail(i, expectedRows, rows, google && actual.results[j] === "" || ollama && actual.idlessResults?.[j] === true ? "name" : "result id");
31905
32380
  }
31906
- return true;
32381
+ if (rows.length !== expectedRows.length)
32382
+ return structureDetail(Math.min(rows.length, expectedRows.length), expectedRows, rows, "count");
32383
+ return;
31907
32384
  } catch {
31908
- return false;
32385
+ return structureDetail(0, undefined, undefined, "count");
31909
32386
  }
31910
32387
  }
31911
32388
 
@@ -32196,8 +32673,9 @@ function registerPiGuardedContext(pi, handler, options = {}) {
32196
32673
  const fields = piConversationFields(payload);
32197
32674
  if (!fields)
32198
32675
  throw new Error("provider conversation identity could not be established");
32199
- if (!piMatchesPreparedStructure(payload, active.preparedStructure))
32200
- throw new Error("provider request does not match this pass's managed dispatch (prepared turn structure)");
32676
+ const structureMismatch = piPreparedStructureMismatch(payload, active.preparedStructure);
32677
+ if (structureMismatch)
32678
+ throw new Error(`provider request does not match this pass's managed dispatch (prepared turn structure); ${structureMismatch}`);
32201
32679
  if (active.dispatched) {
32202
32680
  if (!active.dispatchFields || exactReusablePrefix([{ id: "conversation", fields }], [{ id: "conversation", fields: active.dispatchFields }]) !== 1)
32203
32681
  throw new Error("provider request does not match this pass's managed dispatch");
@@ -32268,7 +32746,7 @@ function registerPiGuardedContext(pi, handler, options = {}) {
32268
32746
  const result = await budget.waitMandatory(Promise.resolve(withSqliteTransformPass2(() => handler(event, ctx, budget))));
32269
32747
  if (result?.messages) {
32270
32748
  active.managedSignature = piManagedSignature(result.messages);
32271
- active.preparedStructure = piPreparedStructure(result.messages);
32749
+ active.preparedStructure = piPreparedStructure(result.messages, fenceEnabled ? ctx.model : undefined);
32272
32750
  budget.completed = true;
32273
32751
  active.ready = true;
32274
32752
  if (inputs)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/pi-magic-context",
3
- "version": "0.49.1",
3
+ "version": "0.49.2",
4
4
  "type": "module",
5
5
  "description": "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",