maka-agent 0.2.0-dev.48.20260923 → 0.2.0-dev.49.20260924

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 (78) hide show
  1. package/dist/acp/session-event-mapper.js +1 -4
  2. package/dist/onboarding-catalog.js +20 -4
  3. package/dist/pi-transcript.js +0 -8
  4. package/dist/pi-tui-pickers.js +1 -1
  5. package/dist/pi-tui-runner.js +6 -4
  6. package/dist/runtime-host-onboarding.js +5 -3
  7. package/dist/runtime-host-session-channel.js +9 -3
  8. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  9. package/node_modules/@maka/core/dist/events.js +13 -0
  10. package/node_modules/@maka/core/dist/llm-connections.js +2 -5
  11. package/node_modules/@maka/core/dist/model-facts.js +2 -4
  12. package/node_modules/@maka/core/dist/model-metadata.generated.js +345 -248
  13. package/node_modules/@maka/core/dist/model-thinking.js +17 -17
  14. package/node_modules/@maka/core/dist/model-web-search.js +7 -9
  15. package/node_modules/@maka/core/dist/models-dev-projection.js +1 -1
  16. package/node_modules/@maka/core/dist/onboarding.js +1 -4
  17. package/node_modules/@maka/core/dist/provider-registry.js +60 -86
  18. package/node_modules/@maka/core/dist/runtime-event.js +2 -2
  19. package/node_modules/@maka/core/dist/runtime-policy/connection-catalog-codec.js +28 -16
  20. package/node_modules/@maka/core/dist/runtime-policy.js +1 -1
  21. package/node_modules/@maka/core/dist/session.js +23 -9
  22. package/node_modules/@maka/core/dist/transcript-search.js +1 -0
  23. package/node_modules/@maka/core/dist/usage-stats/types.js +1 -0
  24. package/node_modules/@maka/eval/dist/harbor-maka-subject.js +3 -0
  25. package/node_modules/@maka/eval/dist/maka-subject.js +8 -1
  26. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +1 -11
  27. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +2 -12
  28. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +3 -71
  29. package/node_modules/@maka/runtime/dist/conversation-copy.js +2 -2
  30. package/node_modules/@maka/runtime/dist/local-web-fetch.js +23 -11
  31. package/node_modules/@maka/runtime/dist/model-adapter.js +10 -5
  32. package/node_modules/@maka/runtime/dist/model-factory.js +33 -30
  33. package/node_modules/@maka/runtime/dist/model-fetcher.js +4 -1
  34. package/node_modules/@maka/runtime/dist/model-runtime.js +3 -9
  35. package/node_modules/@maka/runtime/dist/read-page.js +11 -8
  36. package/node_modules/@maka/runtime/dist/recovery-resolver.js +47 -20
  37. package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +1 -0
  38. package/node_modules/@maka/runtime/dist/scheduled-task-tools.js +39 -8
  39. package/node_modules/@maka/runtime/dist/session-manager.js +12 -2
  40. package/node_modules/@maka/runtime/dist/telemetry/model-pricing.generated.js +141 -134
  41. package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +3 -3
  42. package/node_modules/@maka/runtime/dist/workers/filesystem-worker.js +7 -6
  43. package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +28 -62
  44. package/node_modules/@maka/runtime-host/dist/client/hosted-execution-target.js +7 -1
  45. package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +3 -0
  46. package/node_modules/@maka/runtime-host/dist/protocol/connection-effects.js +6 -3
  47. package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
  48. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +4 -1
  49. package/node_modules/@maka/runtime-host/dist/protocol/prompt-suggestions.js +61 -0
  50. package/node_modules/@maka/runtime-host/dist/protocol/runtime-policy.js +4 -1
  51. package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +2 -1
  52. package/node_modules/@maka/runtime-host/dist/server/connection-effect-coordinator.js +3 -0
  53. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +54 -6
  54. package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +38 -2
  55. package/node_modules/@maka/runtime-host/dist/server/generated-text.js +39 -0
  56. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +8 -0
  57. package/node_modules/@maka/runtime-host/dist/server/prompt-suggestion.js +179 -0
  58. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +2 -2
  59. package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +48 -16
  60. package/node_modules/@maka/runtime-host/dist/server/session-title.js +3 -16
  61. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +38 -3
  62. package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +3 -0
  63. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +6 -13
  64. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +35 -11
  65. package/node_modules/@maka/storage/dist/config-transfer.js +14 -8
  66. package/node_modules/@maka/storage/dist/execution-stores.js +4 -3
  67. package/node_modules/@maka/storage/dist/interaction-store.js +13 -0
  68. package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +28 -17
  69. package/node_modules/@maka/storage/dist/runtime-policy/coordinator.js +9 -3
  70. package/node_modules/@maka/storage/dist/runtime-policy/legacy-custom-connection.js +65 -0
  71. package/node_modules/@maka/storage/dist/runtime-policy/onboarding-transaction.js +10 -5
  72. package/node_modules/@maka/storage/dist/session-bundle-policy.js +11 -0
  73. package/node_modules/@maka/storage/dist/session-store.js +29 -6
  74. package/node_modules/@maka/storage/dist/sqlite-core-execution-schema.js +3 -0
  75. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +125 -7
  76. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +5 -3
  77. package/node_modules/@maka/storage/dist/usage-screen.js +138 -108
  78. package/package.json +1 -1
@@ -41,7 +41,7 @@ import { isCollaborationMode } from './collaboration.js';
41
41
  import { isAgentSwarmAuthorizationSource, isEffectiveOrchestrationSource, isOrchestrationMode, } from './orchestration.js';
42
42
  import { isToolMode } from './tool-mode.js';
43
43
  import { isExecutorId } from './executor-id.js';
44
- import { isRuntimeSystemNoteKind, } from './session.js';
44
+ import { isSystemNoteKind } from './session.js';
45
45
  import { decodeTurnOrigin } from './turn-origin.js';
46
46
  import { defineObjectShape, hasExactShape, isFiniteNumber, isOptionalMember, isOptionalString, isRecord, isStringArray, } from './record-schema.js';
47
47
  import { isPermissionDecisionFields, isPermissionRequestPayload, isUserQuestionRequest, } from './interaction-record-schema.js';
@@ -451,7 +451,7 @@ function isRuntimeEventContent(value) {
451
451
  case 'system_note':
452
452
  return (hasExactShape(value, SYSTEM_NOTE_CONTENT_SHAPE) &&
453
453
  typeof value.note === 'string' &&
454
- isRuntimeSystemNoteKind(value.note));
454
+ isSystemNoteKind(value.note));
455
455
  case 'invocation_opened':
456
456
  return isRuntimeInvocationOpened(value);
457
457
  default:
@@ -16,7 +16,7 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { isModelModality, isRelayProviderType, effectiveBaseUrl, PROVIDER_REGISTRY, providerDefaultsOf, validateSlug, } from '../llm-connections.js';
19
+ import { isModelApiProtocol, isModelModality, effectiveBaseUrl, PROVIDER_REGISTRY, providerDefaultsOf, validateSlug, } from '../llm-connections.js';
20
20
  import { CONNECTION_MODEL_DESCRIPTION_MAX_LENGTH, CONNECTION_MODEL_DISPLAY_NAME_MAX_LENGTH, MAX_PREPENDED_FALLBACK_MODELS, } from '../model-catalog.js';
21
21
  import { DECLARABLE_RELAY_THINKING_LEVELS, isThinkingLevel, } from '../model-thinking.js';
22
22
  import { normalizeOptionalRequestBodyOverlay, RequestCustomizationValidationError, } from '../request-customization.js';
@@ -78,6 +78,7 @@ export function normalizeConnectionCatalogEntryDraft(value) {
78
78
  'name',
79
79
  'providerType',
80
80
  'baseUrl',
81
+ 'defaultApiProtocol',
81
82
  'enabled',
82
83
  'enabledModelIds',
83
84
  'modelOverrides',
@@ -85,6 +86,7 @@ export function normalizeConnectionCatalogEntryDraft(value) {
85
86
  ], ['slug', 'name', 'providerType', 'enabled', 'enabledModelIds']);
86
87
  const providerType = decodeProviderType(item.providerType);
87
88
  const baseUrl = normalizeCatalogConnectionBaseUrl(item.baseUrl, providerType);
89
+ const defaultApiProtocol = decodeDefaultApiProtocol(item.defaultApiProtocol, providerType);
88
90
  const enabledModelIds = decodeConnectionModelIds(item.enabledModelIds);
89
91
  const requestBodyOverlay = item.requestBodyOverlay === undefined
90
92
  ? undefined
@@ -96,6 +98,7 @@ export function normalizeConnectionCatalogEntryDraft(value) {
96
98
  name: decodeConnectionName(item.name),
97
99
  providerType,
98
100
  ...(baseUrl === undefined ? {} : { baseUrl }),
101
+ ...(defaultApiProtocol === undefined ? {} : { defaultApiProtocol }),
99
102
  enabled: booleanValue(item.enabled, 'connection enabled'),
100
103
  enabledModelIds,
101
104
  ...profiles,
@@ -261,28 +264,36 @@ export function decodeModelOverridesTable(value) {
261
264
  * `contextWindow` and `vision` state facts about a model. A user has them when
262
265
  * Maka does not — a model newer than the bundled snapshot, or any model on a
263
266
  * provider with no model-list endpoint — and that need is not confined to
264
- * relays (#1584), so they are legal everywhere.
267
+ * custom connections (#1584), so they are legal everywhere.
265
268
  *
266
- * `thinkingLevels` and `serviceTier` name a wire feature instead. They encode
267
- * into request shapes only the OpenAI-compatible relays accept —
268
- * `reasoning_effort` tiers and priority processing — and
269
- * `supportsRelayFastServiceTier` gates the read side by provider for the same
270
- * reason. A table carrying them on another provider describes a request Maka
271
- * would never send: dead state at best, and on a provider whose wire rejects
272
- * the unknown value, a 400 the user cannot explain.
269
+ * `thinkingLevels` and `serviceTier` name a wire feature instead. Built-in
270
+ * providers take thinking levels from model metadata and never send a declared
271
+ * one; a table carrying them there describes a request Maka would never send.
273
272
  */
274
273
  function assertProfileFieldsFitProvider(profiles, providerType) {
275
- if (!profiles || isRelayProviderType(providerType))
274
+ if (!profiles || providerType === 'custom')
276
275
  return;
277
276
  for (const [modelId, profile] of Object.entries(profiles)) {
278
277
  if (profile.thinkingLevels !== undefined) {
279
- throw domainError(`declared thinking levels for ${modelId} require an OpenAI-compatible connection`);
278
+ throw domainError(`declared thinking levels for ${modelId} require a custom connection`);
280
279
  }
281
280
  if (profile.serviceTier !== undefined) {
282
- throw domainError(`declared service tier for ${modelId} requires an OpenAI-compatible connection`);
281
+ throw domainError(`declared service tier for ${modelId} requires a custom connection`);
283
282
  }
284
283
  }
285
284
  }
285
+ export function decodeDefaultApiProtocol(value, providerType) {
286
+ if (providerType !== 'custom') {
287
+ if (value !== undefined) {
288
+ throw domainError('only a custom connection has a default API protocol');
289
+ }
290
+ return undefined;
291
+ }
292
+ if (!isModelApiProtocol(value)) {
293
+ throw domainError('custom connection default API protocol is invalid');
294
+ }
295
+ return value;
296
+ }
286
297
  // An empty table is not a state worth storing: drafts/canonical entries omit
287
298
  // the key, and updates treat it as the same instruction as `null` (clear).
288
299
  function nonEmptyRelayProfiles(value) {
@@ -297,6 +308,7 @@ export function decodeCanonicalConnectionCatalogEntry(value) {
297
308
  'name',
298
309
  'providerType',
299
310
  'baseUrl',
311
+ 'defaultApiProtocol',
300
312
  'enabled',
301
313
  'enabledModelIds',
302
314
  'modelOverrides',
@@ -320,6 +332,9 @@ export function decodeCanonicalConnectionCatalogEntry(value) {
320
332
  name: item.name,
321
333
  providerType: item.providerType,
322
334
  ...(item.baseUrl === undefined ? {} : { baseUrl: item.baseUrl }),
335
+ ...(item.defaultApiProtocol === undefined
336
+ ? {}
337
+ : { defaultApiProtocol: item.defaultApiProtocol }),
323
338
  enabled: item.enabled,
324
339
  enabledModelIds: item.enabledModelIds,
325
340
  ...(item.modelOverrides === undefined ? {} : { modelOverrides: item.modelOverrides }),
@@ -435,10 +450,7 @@ export function decodeConnectionModel(value) {
435
450
  'capabilities',
436
451
  'modalities',
437
452
  ], ['id']);
438
- if (item.apiProtocol !== undefined &&
439
- item.apiProtocol !== 'openai-chat' &&
440
- item.apiProtocol !== 'openai-responses' &&
441
- item.apiProtocol !== 'anthropic-messages') {
453
+ if (item.apiProtocol !== undefined && !isModelApiProtocol(item.apiProtocol)) {
442
454
  throw domainError('connection model API protocol is invalid');
443
455
  }
444
456
  let capabilities;
@@ -22,7 +22,7 @@ export { WEB_SEARCH_PROVIDERS };
22
22
  export { networkProxyCredentialTarget };
23
23
  export { decodeRuntimePolicyEntityId, RuntimePolicyDomainDecodeError, } from './runtime-policy/domain-codec.js';
24
24
  export { decodeCanonicalRuntimePolicy, normalizeNetworkProxyCredentialTarget, decodeRuntimePolicyV2, decodeRuntimePolicyV3, normalizeNetworkProxyUpdate, normalizeRuntimePolicyMutation, } from './runtime-policy/policy-codec.js';
25
- export { CONNECTION_CATALOG_MAX_CONNECTIONS, CONNECTION_CATALOG_MAX_ENABLED_MODEL_IDS, CONNECTION_CATALOG_MAX_ENTRIES_PER_CONNECTION, CONNECTION_CATALOG_MAX_MODELS_PER_CONNECTION, CONNECTION_MODEL_ID_MAX_LENGTH, CONNECTION_NAME_MAX_LENGTH, decodeCanonicalConnectionBaseUrl, decodeCanonicalConnectionCatalogEntry, decodeConnectionModelId, decodeConnectionCredentialTarget, decodeModelOverridesTable, decodeConnectionModel, decodeConnectionModels, decodeConnectionName, decodeConnectionSlug, decodeConnectionTarget, decodeConnectionTestSummary, decodeConnectionVersionBasis, decodeProviderType, normalizeCatalogConnectionBaseUrl, normalizeConnectionCatalogEntryDraft, normalizeConnectionCatalogEntryUpdate, normalizeConnectionCatalogEntryUpdateForProvider, normalizeConnectionModelDiscoveryResult, canonicalConnectionEffectiveBaseUrl, connectionCredentialTarget, normalizeCreateCatalogConnectionInput, normalizeRemoveCatalogConnectionInput, normalizeSetDefaultConnectionTargetInput, normalizeUpdateCatalogConnectionInput, } from './runtime-policy/connection-catalog-codec.js';
25
+ export { CONNECTION_CATALOG_MAX_CONNECTIONS, CONNECTION_CATALOG_MAX_ENABLED_MODEL_IDS, CONNECTION_CATALOG_MAX_ENTRIES_PER_CONNECTION, CONNECTION_CATALOG_MAX_MODELS_PER_CONNECTION, CONNECTION_MODEL_ID_MAX_LENGTH, CONNECTION_NAME_MAX_LENGTH, decodeCanonicalConnectionBaseUrl, decodeCanonicalConnectionCatalogEntry, decodeConnectionModelId, decodeConnectionCredentialTarget, decodeModelOverridesTable, decodeConnectionModel, decodeConnectionModels, decodeConnectionName, decodeConnectionSlug, decodeConnectionTarget, decodeConnectionTestSummary, decodeConnectionVersionBasis, decodeDefaultApiProtocol, decodeProviderType, normalizeCatalogConnectionBaseUrl, normalizeConnectionCatalogEntryDraft, normalizeConnectionCatalogEntryUpdate, normalizeConnectionCatalogEntryUpdateForProvider, normalizeConnectionModelDiscoveryResult, canonicalConnectionEffectiveBaseUrl, connectionCredentialTarget, normalizeCreateCatalogConnectionInput, normalizeRemoveCatalogConnectionInput, normalizeSetDefaultConnectionTargetInput, normalizeUpdateCatalogConnectionInput, } from './runtime-policy/connection-catalog-codec.js';
26
26
  export { decodeModelCatalogEntry } from './runtime-policy/model-catalog-entry-codec.js';
27
27
  export { decodeCredentialLocator, decodeCredentialStatus, decodeCredentialVersionBasis, normalizeCredentialSecret, normalizeDeleteCredentialInput, normalizeSetCredentialInput, } from './runtime-policy/credential-vault-codec.js';
28
28
  export { normalizeRequestBodyOverlay, normalizeOptionalRequestBodyOverlay, normalizeRequestHeaderUpdates, normalizeRequestHeaders, parseRequestHeaders, REQUEST_BODY_OVERLAY_MAX_BYTES, REQUEST_HEADERS_MAX_BYTES, RequestCustomizationValidationError, serializeRequestHeaders, } from './request-customization.js';
@@ -17,6 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  import { isWorkHubActionReceipt } from './workhub-action-result.js';
20
+ import { decodeInteractionRequest, decodeInteractionCanonicalOutcome, isInteractionCanonicalOutcomeValidForRequest, } from './interaction.js';
20
21
  import { isExecutorId } from './executor-id.js';
21
22
  import { isThinkingLevel } from './model-thinking.js';
22
23
  import { MODEL_FAILURE_MESSAGE_MAX_BYTES, isModelRetryDecision, } from './model-failure.js';
@@ -352,7 +353,6 @@ function isWorkHubDelegationStopResolution(outcome, targetTurnId) {
352
353
  export const RUNTIME_SYSTEM_NOTE_KINDS = [
353
354
  'context_compacted',
354
355
  'context_compaction_failed_open',
355
- 'context_provider_dropping',
356
356
  'context_window_suggestion',
357
357
  'context_window_overrun',
358
358
  'context_reported_window_exceeded',
@@ -360,9 +360,9 @@ export const RUNTIME_SYSTEM_NOTE_KINDS = [
360
360
  'step_limit',
361
361
  ];
362
362
  /**
363
- * Notes only legacy transcripts carry, still decoded so those rows stay
364
- * readable. Nothing writes them: the Session header and the invocation's
365
- * opening and terminal facts already own what each of them said.
363
+ * Notes nothing writes any more, still decoded so old transcripts and run
364
+ * ledgers stay readable, and never shown. The session-level ones are owned by
365
+ * the Session header and the invocation's opening and terminal facts.
366
366
  */
367
367
  export const RETIRED_SYSTEM_NOTE_KINDS = [
368
368
  'session_start',
@@ -371,10 +371,14 @@ export const RETIRED_SYSTEM_NOTE_KINDS = [
371
371
  'model_change',
372
372
  'error',
373
373
  'abort',
374
+ 'context_provider_dropping',
374
375
  ];
375
376
  export function isRuntimeSystemNoteKind(kind) {
376
377
  return RUNTIME_SYSTEM_NOTE_KINDS.includes(kind);
377
378
  }
379
+ export function isSystemNoteKind(kind) {
380
+ return (isRuntimeSystemNoteKind(kind) || RETIRED_SYSTEM_NOTE_KINDS.includes(kind));
381
+ }
378
382
  const USER_MESSAGE_SHAPE = defineObjectShape()(['type', 'id', 'turnId', 'ts', 'text'], [
379
383
  'displayText',
380
384
  'attachments',
@@ -407,6 +411,7 @@ const TOOL_RESULT_MESSAGE_SHAPE = defineObjectShape()(['type', 'id', 'turnId', '
407
411
  'parentToolCallId',
408
412
  'parentOperationId',
409
413
  ]);
414
+ const FORM_INTERACTION_MESSAGE_SHAPE = defineObjectShape()(['type', 'id', 'turnId', 'ts', 'request', 'outcome'], []);
410
415
  const PERMISSION_DECISION_MESSAGE_SHAPE = defineObjectShape()(['type', 'id', 'turnId', 'ts', 'toolUseId', 'toolName', 'decision'], ['rememberForTurn', 'reviewer', 'rationale', 'riskLevel', 'hint']);
411
416
  const TOKEN_USAGE_MESSAGE_SHAPE = defineObjectShape()(['type', 'id', 'turnId', 'ts', 'input', 'output'], [
412
417
  'cacheHitInput',
@@ -556,10 +561,6 @@ const WORKHUB_DELEGATION_HOST_PATH_WORKSPACE_SHAPE = defineObjectShape()(['kind'
556
561
  const SYSTEM_NOTE_MESSAGE_SHAPE = defineObjectShape()(['type', 'id', 'ts', 'kind'], ['turnId', 'data']);
557
562
  const ASSISTANT_THINKING_PART_SHAPE = defineObjectShape()(['text'], ['signature', 'providerOptions']);
558
563
  const ASSISTANT_THINKING_SHAPE = defineObjectShape()(['text'], ['signature', 'providerOptions', 'parts']);
559
- const SYSTEM_NOTE_KINDS = new Set([
560
- ...RUNTIME_SYSTEM_NOTE_KINDS,
561
- ...RETIRED_SYSTEM_NOTE_KINDS,
562
- ]);
563
564
  export function decodeCanonicalMessage(value) {
564
565
  return decodeMessage(value, decodeCanonicalToolResultContent);
565
566
  }
@@ -637,6 +638,19 @@ function decodeMessage(value, decodeToolResultContent) {
637
638
  isToolActivityIdentity(message))
638
639
  return message;
639
640
  break;
641
+ case 'form_interaction':
642
+ if (hasMessageEnvelope(message, true) &&
643
+ hasExactShape(message, FORM_INTERACTION_MESSAGE_SHAPE)) {
644
+ const request = decodeInteractionRequest(message.request);
645
+ const outcome = decodeInteractionCanonicalOutcome(message.outcome);
646
+ if ((request.kind === 'form' || request.kind === 'question') &&
647
+ (outcome.kind === 'form_answer' ||
648
+ outcome.kind === 'question_answer' ||
649
+ outcome.kind === 'closure') &&
650
+ isInteractionCanonicalOutcomeValidForRequest(request, outcome))
651
+ return { ...message, request, outcome };
652
+ }
653
+ break;
640
654
  case 'permission_decision':
641
655
  if (hasExactShape(message, PERMISSION_DECISION_MESSAGE_SHAPE) &&
642
656
  hasMessageEnvelope(message, true) &&
@@ -680,7 +694,7 @@ function decodeMessage(value, decodeToolResultContent) {
680
694
  if (hasExactShape(message, SYSTEM_NOTE_MESSAGE_SHAPE) &&
681
695
  hasMessageEnvelope(message, false) &&
682
696
  isOptionalString(message.turnId) &&
683
- SYSTEM_NOTE_KINDS.has(message.kind))
697
+ isSystemNoteKind(message.kind))
684
698
  return message;
685
699
  break;
686
700
  }
@@ -36,6 +36,7 @@ export function threadSearchMatchKind(message) {
36
36
  return 'tool_intent';
37
37
  case 'tool_result':
38
38
  return 'tool_result';
39
+ case 'form_interaction':
39
40
  case 'permission_decision':
40
41
  case 'token_usage':
41
42
  case 'turn_state':
@@ -27,6 +27,7 @@ export const MODEL_CALL_KINDS = [
27
27
  'goal_evaluation',
28
28
  'session_title',
29
29
  'session_recap',
30
+ 'prompt_suggestion',
30
31
  'daily_review',
31
32
  'memory_extraction',
32
33
  'workhub_intent',
@@ -62,6 +62,9 @@ try {
62
62
  ? {
63
63
  connection: {
64
64
  providerType: payload.connection.providerType,
65
+ ...(payload.connection.defaultApiProtocol === undefined
66
+ ? {}
67
+ : { defaultApiProtocol: payload.connection.defaultApiProtocol }),
65
68
  apiKey: process.env[payload.connection.apiKeyEnvironment] ?? '',
66
69
  },
67
70
  }
@@ -17,7 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  import { randomUUID } from 'node:crypto';
20
- import { PROVIDER_REGISTRY } from '@maka/core/llm-connections';
20
+ import { isModelApiProtocol, PROVIDER_REGISTRY } from '@maka/core/llm-connections';
21
21
  import { isThinkingLevel } from '@maka/core/model-thinking';
22
22
  import { isSessionToolProfile } from '@maka/core/session';
23
23
  import { decodeHostedExecutionProjection } from '@maka/runtime-host/protocol';
@@ -63,6 +63,9 @@ export function createMakaSubjectAdapter() {
63
63
  ? {
64
64
  connection: {
65
65
  providerType: config.providerType,
66
+ ...(config.defaultApiProtocol === undefined
67
+ ? {}
68
+ : { defaultApiProtocol: config.defaultApiProtocol }),
66
69
  apiKeyEnvironment: config.apiKeyEnvironment,
67
70
  },
68
71
  }
@@ -237,6 +240,7 @@ function decodeConfig(value) {
237
240
  'connectionSlug',
238
241
  'model',
239
242
  ...(Object.hasOwn(value, 'providerType') ? ['providerType', 'apiKeyEnvironment'] : []),
243
+ ...(value.providerType === 'custom' ? ['defaultApiProtocol'] : []),
240
244
  ...(Object.hasOwn(value, 'thinkingLevel') ? ['thinkingLevel'] : []),
241
245
  'permissionMode',
242
246
  'collaborationMode',
@@ -249,6 +253,9 @@ function decodeConfig(value) {
249
253
  !Object.hasOwn(PROVIDER_REGISTRY, String(config.providerType))) {
250
254
  throw new Error('Maka config.providerType is invalid');
251
255
  }
256
+ if (config.providerType === 'custom' && !isModelApiProtocol(config.defaultApiProtocol)) {
257
+ throw new Error('Maka config.defaultApiProtocol is invalid');
258
+ }
252
259
  if (config.thinkingLevel !== undefined && !isThinkingLevel(config.thinkingLevel)) {
253
260
  throw new Error('Maka config.thinkingLevel is invalid');
254
261
  }
@@ -91,17 +91,7 @@ export class AiSdkBackend {
91
91
  */
92
92
  activeTurns = new Set();
93
93
  compaction;
94
- /**
95
- * The provider has been reported dropping context, for this backend.
96
- *
97
- * Not per send: the condition persists once a provider starts truncating, so
98
- * a note on every later turn would repeat one fact the user has already been
99
- * told. The scope is this backend's lifetime rather than the Session's, so a
100
- * backend that is disposed and rebuilt may say it once more.
101
- */
102
- turnSessionState = {
103
- contextProviderDroppingReported: false,
104
- };
94
+ turnSessionState = {};
105
95
  constructor(input) {
106
96
  this.input = input;
107
97
  this.sessionId = input.sessionId;
@@ -536,7 +536,6 @@ export class AiSdkCompaction {
536
536
  if (persisted) {
537
537
  state.baselineTokens = persisted.inputTokens + (persisted.outputTokens ?? 0);
538
538
  state.lastAcceptedTotalTokens = state.baselineTokens;
539
- state.priorAcceptedInputTokens = persisted.inputTokens;
540
539
  }
541
540
  if (persisted)
542
541
  state.replyReserveTokens = replyReserveTokens(persisted.outputTokens);
@@ -1034,9 +1033,8 @@ export class MidTurnCapacityCompactState {
1034
1033
  }
1035
1034
  /**
1036
1035
  * What has reshaped the request since the last one a provider accepted. The
1037
- * turn clears it at that acceptance, every shaper records itself here, and
1038
- * every consumer reads it here — an empty set is the only proof that the next
1039
- * request is a pure append of its predecessor.
1036
+ * turn clears it at that acceptance; overflow recovery reads it so a request
1037
+ * that was already folded or stripped of images is not reshaped again.
1040
1038
  */
1041
1039
  stepShaping = new Set();
1042
1040
  /**
@@ -1050,14 +1048,6 @@ export class MidTurnCapacityCompactState {
1050
1048
  omittedImageToolResults = new Map();
1051
1049
  /** Malformed summaries spend one bounded repair budget for this whole Turn. */
1052
1050
  summarizerFailure;
1053
- /**
1054
- * Input tokens of the last request a provider accepted before this send.
1055
- *
1056
- * Input against input, across the send boundary: the first request of a send
1057
- * has no earlier step to compare with, and `baselineTokens` counts the reply
1058
- * too, which the next request does not always carry.
1059
- */
1060
- priorAcceptedInputTokens;
1061
1051
  constructor(headAnchor, priorContentEvents, priorInvocations,
1062
1052
  /**
1063
1053
  * The Maka window: the context window the USER declared for this model,
@@ -695,8 +695,6 @@ export class AiSdkTurn {
695
695
  // result.usage.inputTokens is cumulative across steps and would produce
696
696
  // misleading >100% percentages, so the per-step value is captured here.
697
697
  let lastStepInputTokens;
698
- /** Tool count of the request that produced `lastStepInputTokens`. */
699
- let lastStepActiveToolCount;
700
698
  // Output tokens of the same step: with the input they are the baseline the
701
699
  // next request is judged from (everything the model produced is re-sent).
702
700
  let lastStepOutputTokens;
@@ -977,8 +975,6 @@ export class AiSdkTurn {
977
975
  const turnEvents = await loadDurableTurnEvents();
978
976
  const pruned = await this.deps.compaction.pruneToolResults(turnEvents, turnId);
979
977
  if (pruned.stats) {
980
- if (pruned.stats.prunedToolResults > 0)
981
- midTurnState?.stepShaping.add('prune');
982
978
  contextBudgetForTelemetry = addToolResultPruneStats(contextBudgetForTelemetry ?? minimalContextBudgetDiagnostic(), pruned.stats);
983
979
  }
984
980
  const projectionCheckpoint = midTurnState?.projectionCheckpoint;
@@ -1151,14 +1147,6 @@ export class AiSdkTurn {
1151
1147
  ? codeModeCatalogPrompt
1152
1148
  : undefined,
1153
1149
  ]);
1154
- // A finalization step resolves an empty tool set, so its request
1155
- // legitimately drops several thousand schema tokens with no fold,
1156
- // prune or image omission. Maka shaped that request; the provider did
1157
- // not drop anything.
1158
- if (lastStepActiveToolCount !== undefined &&
1159
- activeToolsForRequest.length < lastStepActiveToolCount) {
1160
- midTurnState?.stepShaping.add('tools');
1161
- }
1162
1150
  const requestCompositionId = this.runId && this.deps.backend.recordRequestComposition
1163
1151
  ? await this.deps.backend.recordRequestComposition(this.runId, {
1164
1152
  compositionId: this.deps.newId(),
@@ -1440,61 +1428,6 @@ export class AiSdkTurn {
1440
1428
  providerStepUsage = stepUsage;
1441
1429
  if (!stepUsage)
1442
1430
  sawUnusableStepUsage = true;
1443
- // Silent eviction / rewrite check (#4559): this step only
1444
- // appended (no fold, no prune, no image omission) yet the
1445
- // provider counted no more input tokens than for the previous
1446
- // request. Not-greater, not strictly-fewer: a provider that
1447
- // truncates to a fixed window (Ollama's `num_ctx`) reports the
1448
- // same total on every later request while Maka keeps
1449
- // appending, so a plateau is the signal, and an equal count
1450
- // after an append is already impossible without provider-side
1451
- // eviction or rewriting. Input against input: the previous
1452
- // reply's reasoning may not be resent, so input + output is
1453
- // not the floor of the next input on every wire.
1454
- const completedRequestIndex = runtimeSteps - 1;
1455
- // Across the send boundary the comparison is the same one,
1456
- // against the last request a provider accepted before this
1457
- // send. A provider that truncates to a fixed window reports
1458
- // the same input on every later request while the user keeps
1459
- // adding turns, and a send of one or two steps never sees
1460
- // that from the inside: the live evidence plateaus at 3,716
1461
- // input tokens across eight turns with nothing reported
1462
- // (#4623). The first request of a send therefore compares
1463
- // against the persisted anchor, which is route-validated
1464
- // where it is read.
1465
- const acrossSends = completedRequestIndex === 0;
1466
- const priorInput = acrossSends
1467
- ? midTurnState?.priorAcceptedInputTokens
1468
- : lastStepInputTokens;
1469
- if (!this.deps.session.contextProviderDroppingReported &&
1470
- midTurnState &&
1471
- priorInput !== undefined &&
1472
- midTurnState.stepShaping.size === 0 &&
1473
- stepUsage !== undefined &&
1474
- Number.isFinite(stepUsage.inputTokens) &&
1475
- stepUsage.inputTokens > 0 &&
1476
- // Across sends the test is equality, not "did not grow".
1477
- // Inside a send Maka knows it only appended, so any
1478
- // shortfall is the provider's. Across the boundary it does
1479
- // not: a manual compaction leaves the pre-compaction anchor
1480
- // behind, a turn can carry a smaller tool set, and a user
1481
- // can edit or branch history. All three shrink the input
1482
- // legitimately, and none of them lands on exactly the same
1483
- // count. A provider truncating to a fixed window does, on
1484
- // every later request.
1485
- (acrossSends
1486
- ? stepUsage.inputTokens === priorInput
1487
- : stepUsage.inputTokens <= priorInput)) {
1488
- this.deps.session.contextProviderDroppingReported = true;
1489
- await this.recordSystemNote('context_provider_dropping', turnId, {
1490
- inputTokens: stepUsage.inputTokens,
1491
- priorInputTokens: priorInput,
1492
- });
1493
- }
1494
- // Clear here, not at the top of the next step: the continuation
1495
- // lane archives its prune below, after this point, and archiving
1496
- // is idempotent — the next step's re-projection reports no prune,
1497
- // so a clear above it would lose the only record of this one.
1498
1431
  midTurnState?.stepShaping.clear();
1499
1432
  // Fail closed: reset on every step boundary so a missing final
1500
1433
  // step's usage does not leave a stale value from an earlier step.
@@ -1520,9 +1453,9 @@ export class AiSdkTurn {
1520
1453
  }
1521
1454
  // Nothing declared, and the provider accepted a request past
1522
1455
  // the window this model reports. Every other signal in this
1523
- // design stays dark there: no rejection to recover from, no
1524
- // plateau to read, and no declaration to arm the proactive
1525
- // threshold, so the session degrades quietly and
1456
+ // design stays dark there: no rejection to recover from and
1457
+ // no declaration to arm the proactive threshold, so the
1458
+ // session degrades quietly and
1526
1459
  // indefinitely (#4634). Report the two real numbers and
1527
1460
  // leave the decision with the user: a reported window is a
1528
1461
  // hint, and Maka still declares nothing on their behalf.
@@ -1560,7 +1493,6 @@ export class AiSdkTurn {
1560
1493
  }
1561
1494
  lastStepInputTokens = stepUsage?.inputTokens;
1562
1495
  lastStepOutputTokens = stepUsage?.outputTokens;
1563
- lastStepActiveToolCount = activeToolsForRequest.length;
1564
1496
  // A `finishReason: length` is deliberately not a trigger. The
1565
1497
  // reply may have been cut because the provider ran out of
1566
1498
  // window room, or because the provider's own output cap is
@@ -39,7 +39,7 @@ import { baseToolResultProjection, decodeLedgerTransition, reduceEffectiveModelP
39
39
  import { archivedToolResultProjection } from './tool-result-archive-transition.js';
40
40
  import { serializeToolResultProjectionV1 } from './tool-result-archive-encoding.js';
41
41
  import { createHash } from 'node:crypto';
42
- import { readToolResultPage, readableToolResult, resolveReadInput, READ_PAGE_MAX_CHARS, } from './read-page.js';
42
+ import { readToolResultPage, readableToolResult, resolveReadInput, READ_PAGE_MAX_BYTES, } from './read-page.js';
43
43
  /** Walks every typed StorageRef site reached by conversation-copy rewriting. */
44
44
  function collectConversationCopyStorageRefs(input) {
45
45
  const refs = [];
@@ -937,7 +937,7 @@ function cloneModelProjectionTransition(event, references, clonedRuntimeEvents,
937
937
  });
938
938
  if (rewritten.page) {
939
939
  delete rewritten.page;
940
- rewritten.page = readToolResultPage(serialized, { path: rewritten.resourceRef }, READ_PAGE_MAX_CHARS - JSON.stringify(rewritten).length - 32);
940
+ rewritten.page = readToolResultPage(serialized, { path: rewritten.resourceRef }, READ_PAGE_MAX_BYTES - Buffer.byteLength(JSON.stringify(rewritten)) - 32);
941
941
  }
942
942
  references.ledgerArchives?.set(placeholder.resourceRef ?? buildToolResultArchiveResourceRef(placeholder), rewritten);
943
943
  }
@@ -144,24 +144,36 @@ function htmlToMarkdown(html, pageUrl) {
144
144
  assertSafeHtmlNesting(html);
145
145
  const { document } = parseHTML(html);
146
146
  const baseHref = document.querySelector('base[href]')?.getAttribute('href');
147
- let linkBaseUrl = pageUrl;
147
+ let baseUrl = pageUrl;
148
148
  if (baseHref) {
149
149
  try {
150
- linkBaseUrl = new URL(baseHref, pageUrl).toString();
150
+ baseUrl = new URL(baseHref, pageUrl).toString();
151
151
  }
152
152
  catch {
153
153
  // Fall back to the response URL for a malformed page-authored base URL.
154
154
  }
155
155
  }
156
- for (const element of document.querySelectorAll('[href]')) {
157
- const href = element.getAttribute('href');
158
- if (!href)
159
- continue;
160
- try {
161
- element.setAttribute('href', new URL(href, linkBaseUrl).toString());
162
- }
163
- catch {
164
- // Keep malformed page-authored links as-is.
156
+ const documentBase = document.querySelector('base') ?? document.createElement('base');
157
+ documentBase.setAttribute('href', baseUrl);
158
+ if (!documentBase.parentNode)
159
+ document.head?.prepend(documentBase);
160
+ // Turndown renders both `<a href>` and `<img src>` as Markdown links, so each
161
+ // has to carry an absolute URL: a relative path stops meaning anything once
162
+ // the model reads the Markdown apart from the page it was extracted from.
163
+ for (const [selector, attribute] of [
164
+ ['[href]', 'href'],
165
+ ['img[src]', 'src'],
166
+ ]) {
167
+ for (const element of document.querySelectorAll(selector)) {
168
+ const value = element.getAttribute(attribute);
169
+ if (!value)
170
+ continue;
171
+ try {
172
+ element.setAttribute(attribute, new URL(value, baseUrl).toString());
173
+ }
174
+ catch {
175
+ // Keep malformed page-authored values as-is.
176
+ }
165
177
  }
166
178
  }
167
179
  const article = new Readability(document).parse();
@@ -152,7 +152,12 @@ export class ModelAdapter {
152
152
  const providerToolName = (name) => usesOpenAiResponsesAdapter && name === TOOL_SEARCH_NAME ? TOOL_SEARCH_PROVIDER_NAME : name;
153
153
  const runtimeToolName = (name) => usesOpenAiResponsesAdapter && name === TOOL_SEARCH_PROVIDER_NAME ? TOOL_SEARCH_NAME : name;
154
154
  const sdkTools = lowerModelTools(input.tools);
155
- if (usesOpenAiResponsesAdapter && sdkTools[TOOL_SEARCH_NAME] !== undefined) {
155
+ // Prose names the alias only when the provider can call it. In Code Mode
156
+ // tool_search is nested inside exec under its runtime name, so the
157
+ // catalog prompt must keep that name.
158
+ const providerExposesToolSearch = usesOpenAiResponsesAdapter && sdkTools[TOOL_SEARCH_NAME] !== undefined;
159
+ const providerTextToolName = (name) => providerExposesToolSearch ? providerToolName(name) : name;
160
+ if (providerExposesToolSearch) {
156
161
  sdkTools[TOOL_SEARCH_PROVIDER_NAME] = sdkTools[TOOL_SEARCH_NAME];
157
162
  delete sdkTools[TOOL_SEARCH_NAME];
158
163
  }
@@ -163,9 +168,9 @@ export class ModelAdapter {
163
168
  const continuation = responsesLane
164
169
  ? planOpenAiResponsesContinuation(fullMessages, this.openAiResponsesTransportState.semanticBaseline(responsesLane))
165
170
  : { messages: fullMessages };
166
- const providerMessages = remapModelMessageToolNames(continuation.messages, providerToolName);
171
+ const providerMessages = remapModelMessageToolNames(continuation.messages, providerToolName, providerTextToolName);
167
172
  const providerSystem = input.system
168
- ? remapProviderToolNamesInText(input.system, providerToolName)
173
+ ? remapProviderToolNamesInText(input.system, providerTextToolName)
169
174
  : undefined;
170
175
  const providerOptions = usesNativeOpenAiResponses(this.input.connection, this.runtime)
171
176
  ? mergeOpenAiResponsesProviderOptions(this.input.providerOptions, this.input.sessionId ?? this.input.connection.slug, continuation.previousResponseId)
@@ -914,7 +919,7 @@ function lowerChatToolImages(messages) {
914
919
  * OpenAI Responses reserves the provider name `tool_search`. Keep Maka's
915
920
  * persisted/history name intact and translate only the provider-bound copy.
916
921
  */
917
- function remapModelMessageToolNames(messages, providerToolName) {
922
+ function remapModelMessageToolNames(messages, providerToolName, providerTextToolName) {
918
923
  const remapContent = (content) => content.map((part) => {
919
924
  if ((part.type === 'tool-call' || part.type === 'tool-result') &&
920
925
  'toolName' in part &&
@@ -925,7 +930,7 @@ function remapModelMessageToolNames(messages, providerToolName) {
925
930
  typeof remapped.output.value === 'string') {
926
931
  remapped.output = {
927
932
  ...remapped.output,
928
- value: remapProviderToolNamesInText(remapped.output.value, providerToolName),
933
+ value: remapProviderToolNamesInText(remapped.output.value, providerTextToolName),
929
934
  };
930
935
  }
931
936
  }