ummaya 0.2.2 → 0.2.4

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 (111) hide show
  1. package/README.md +2 -1
  2. package/npm-shrinkwrap.json +2 -2
  3. package/package.json +1 -1
  4. package/prompts/manifest.yaml +2 -2
  5. package/prompts/session_guidance_v1.md +3 -1
  6. package/prompts/system_v1.md +8 -7
  7. package/pyproject.toml +2 -7
  8. package/src/ummaya/context/builder.py +17 -11
  9. package/src/ummaya/engine/engine.py +27 -7
  10. package/src/ummaya/engine/query.py +20 -0
  11. package/src/ummaya/evidence/__init__.py +25 -0
  12. package/src/ummaya/evidence/__main__.py +7 -0
  13. package/src/ummaya/evidence/models.py +58 -0
  14. package/src/ummaya/evidence/runner.py +308 -0
  15. package/src/ummaya/evidence/task_registry.py +264 -0
  16. package/src/ummaya/ipc/frame_schema.py +47 -0
  17. package/src/ummaya/ipc/stdio.py +1349 -90
  18. package/src/ummaya/llm/client.py +132 -56
  19. package/src/ummaya/llm/reasoning.py +84 -0
  20. package/src/ummaya/tools/discovery_bridge.py +17 -1
  21. package/src/ummaya/tools/executor.py +32 -12
  22. package/src/ummaya/tools/geocoding/kakao_client.py +1 -2
  23. package/src/ummaya/tools/kma/apihub_catalog.py +984 -1
  24. package/src/ummaya/tools/kma/apihub_structured_adapter.py +86 -6
  25. package/src/ummaya/tools/kma/apihub_url_adapter.py +593 -0
  26. package/src/ummaya/tools/kma/apihub_url_catalog.py +296 -0
  27. package/src/ummaya/tools/location_adapters.py +8 -6
  28. package/src/ummaya/tools/manifest_metadata.py +16 -3
  29. package/src/ummaya/tools/mvp_surface.py +2 -2
  30. package/src/ummaya/tools/nmc/emergency_search.py +8 -6
  31. package/src/ummaya/tools/register_all.py +9 -0
  32. package/src/ummaya/tools/resolve_location.py +4 -4
  33. package/src/ummaya/tools/search.py +664 -18
  34. package/src/ummaya/tools/verified_data_go_kr/_manifest.py +115 -25
  35. package/src/ummaya/tools/verified_data_go_kr/airkorea_air_quality.py +109 -4
  36. package/src/ummaya/tools/verified_data_go_kr/nmc_aed_site.py +108 -2
  37. package/src/ummaya/tools/verified_data_go_kr/pps_bid_public_info.py +174 -9
  38. package/src/ummaya/tools/verified_data_go_kr/tago_bus_arrival.py +66 -3
  39. package/src/ummaya/tools/verified_data_go_kr/tago_bus_location.py +12 -2
  40. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route.py +8 -2
  41. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route_station.py +114 -0
  42. package/src/ummaya/tools/verified_data_go_kr/tago_bus_station.py +14 -3
  43. package/src/ummaya/tools/verify_canonical_map.py +21 -0
  44. package/tui/package.json +1 -2
  45. package/tui/src/QueryEngine.ts +4 -0
  46. package/tui/src/cli/handlers/auth.ts +1 -1
  47. package/tui/src/cli/handlers/mcp.tsx +3 -3
  48. package/tui/src/cli/print.ts +69 -18
  49. package/tui/src/cli/update.ts +13 -13
  50. package/tui/src/commands/copy/index.ts +1 -1
  51. package/tui/src/commands/cost/cost.ts +2 -2
  52. package/tui/src/commands/init-verifiers.ts +5 -5
  53. package/tui/src/commands/init.ts +30 -30
  54. package/tui/src/commands/insights.ts +43 -43
  55. package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
  56. package/tui/src/commands/install-github-app/setupGitHubActions.ts +3 -3
  57. package/tui/src/commands/install.tsx +5 -5
  58. package/tui/src/commands/mcp/addCommand.ts +5 -5
  59. package/tui/src/commands/mcp/xaaIdpCommand.ts +2 -2
  60. package/tui/src/commands/plugin/ManageMarketplaces.tsx +2 -2
  61. package/tui/src/commands/reasoning/index.ts +13 -0
  62. package/tui/src/commands/reasoning/reasoning.tsx +177 -0
  63. package/tui/src/commands/thinkback/thinkback.tsx +3 -3
  64. package/tui/src/commands.ts +2 -0
  65. package/tui/src/components/Messages.tsx +2 -1
  66. package/tui/src/components/Spinner.tsx +2 -2
  67. package/tui/src/components/design-system/LoadingState.tsx +2 -2
  68. package/tui/src/ipc/codec.ts +26 -0
  69. package/tui/src/ipc/frames.generated.ts +398 -303
  70. package/tui/src/ipc/llmClient.ts +130 -51
  71. package/tui/src/ipc/llmTypes.ts +16 -1
  72. package/tui/src/ipc/schema/frame.schema.json +1 -3475
  73. package/tui/src/main.tsx +3 -0
  74. package/tui/src/query.ts +467 -2
  75. package/tui/src/screens/REPL.tsx +3 -3
  76. package/tui/src/services/api/claude.ts +54 -25
  77. package/tui/src/services/api/client.ts +33 -12
  78. package/tui/src/services/api/ummaya.ts +70 -16
  79. package/tui/src/skills/bundled/stuck.ts +12 -12
  80. package/tui/src/state/AppStateStore.ts +7 -0
  81. package/tui/src/tools/AdapterTool/AdapterTool.ts +590 -7
  82. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +43 -17
  83. package/tui/src/tools/LookupPrimitive/prompt.ts +7 -6
  84. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +40 -19
  85. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +25 -9
  86. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +25 -9
  87. package/tui/src/tools/_shared/citizenUserText.ts +49 -0
  88. package/tui/src/tools/_shared/directPublicDataGuard.ts +362 -0
  89. package/tui/src/tools/_shared/kmaAnalysisGuard.ts +197 -0
  90. package/tui/src/tools/_shared/kmaAviationGuard.ts +70 -0
  91. package/tui/src/tools/_shared/locationInputRepair.ts +112 -0
  92. package/tui/src/tools/_shared/nmcAedGuard.ts +234 -0
  93. package/tui/src/tools/_shared/protectedCheckGuard.ts +207 -0
  94. package/tui/src/tools/_shared/rootPrimitiveInput.ts +67 -0
  95. package/tui/src/tools/_shared/textToolCallGuard.ts +91 -0
  96. package/tui/src/tools/_shared/toolChoiceRepair.ts +866 -0
  97. package/tui/src/utils/attachments.ts +1 -1
  98. package/tui/src/utils/kExaoneReasoning.ts +138 -0
  99. package/tui/src/utils/messages.ts +1 -0
  100. package/tui/src/utils/multiToolLayout.ts +13 -0
  101. package/tui/src/utils/processUserInput/processSlashCommand.tsx +2 -2
  102. package/tui/src/utils/processUserInput/processUserInput.ts +26 -0
  103. package/tui/src/utils/settings/applySettingsChange.ts +4 -0
  104. package/tui/src/utils/settings/types.ts +9 -3
  105. package/tui/src/utils/stats.ts +1 -1
  106. package/uv.lock +1 -15
  107. package/assets/copilot-gate-logo.svg +0 -58
  108. package/assets/govon-logo.svg +0 -40
  109. package/src/ummaya/eval/__init__.py +0 -5
  110. package/src/ummaya/eval/retrieval.py +0 -713
  111. package/tui/src/utils/messageStream.ts +0 -186
package/tui/src/main.tsx CHANGED
@@ -23,6 +23,7 @@ import { checkHasTrustDialogAccepted, getGlobalConfig, getRemoteControlAtStartup
23
23
  import { seedEarlyInput, stopCapturingEarlyInput } from './utils/earlyInput.js';
24
24
  import { getInitialEffortSetting, parseEffortValue } from './utils/effort.js';
25
25
  import { getInitialFastModeSetting, isFastModeEnabled, prefetchFastModeStatus, resolveFastModeStatusFromCache } from './utils/fastMode.js';
26
+ import { getInitialReasoningModeSetting } from './utils/kExaoneReasoning.js';
26
27
  import { applyConfigEnvironmentVariables } from './utils/managedEnv.js';
27
28
  import { createSystemMessage } from './utils/systemMessageFactories.js';
28
29
  import { createUserMessage } from './utils/userMessageFactories.js';
@@ -1774,6 +1775,7 @@ async function run(): Promise<CommanderCommand> {
1774
1775
  },
1775
1776
  toolPermissionContext,
1776
1777
  effortValue: parseEffortValue(options.effort) ?? getInitialEffortSetting(),
1778
+ reasoningMode: getInitialReasoningModeSetting(),
1777
1779
  ...(isFastModeEnabled() && {
1778
1780
  fastMode: getInitialFastModeSetting(effectiveModel ?? null)
1779
1781
  }),
@@ -2105,6 +2107,7 @@ async function run(): Promise<CommanderCommand> {
2105
2107
  })
2106
2108
  } : null,
2107
2109
  effortValue: parseEffortValue(options.effort) ?? getInitialEffortSetting(),
2110
+ reasoningMode: getInitialReasoningModeSetting(),
2108
2111
  activeOverlays: new Set<string>(),
2109
2112
  fastMode: getInitialFastModeSetting(resolvedInitialModel),
2110
2113
  ...(isAdvisorEnabled() && advisorModel && {
package/tui/src/query.ts CHANGED
@@ -99,6 +99,38 @@ import { runTools } from './services/tools/toolOrchestration.js'
99
99
  import { applyToolResultBudget } from './utils/toolResultStorage.js'
100
100
  import { recordContentReplacement } from './utils/sessionStorage.js'
101
101
  import { handleStopHooks } from './query/stopHooks.js'
102
+ import {
103
+ buildNmcAedCompletionPromptIfNeeded,
104
+ buildNmcAedFollowupPromptIfNeeded,
105
+ } from './tools/_shared/nmcAedGuard.js'
106
+ import {
107
+ buildKmaAnalysisCompletionPromptIfNeeded,
108
+ buildKmaAnalysisFinalAnswerRepairPromptIfNeeded,
109
+ buildKmaAnalysisMissingToolPromptIfNeeded,
110
+ shouldWithholdKmaAnalysisToolCallText,
111
+ } from './tools/_shared/kmaAnalysisGuard.js'
112
+ import {
113
+ buildProtectedCheckCompletionPromptIfNeeded,
114
+ buildProtectedCheckFinalAnswerRepairPromptIfNeeded,
115
+ shouldWithholdProtectedCheckToolCallText,
116
+ } from './tools/_shared/protectedCheckGuard.js'
117
+ import {
118
+ buildAirKoreaCompletionPromptIfNeeded,
119
+ buildAirKoreaFinalAnswerRepairPromptIfNeeded,
120
+ buildGenericPendingFinalAnswerRepairPromptIfNeeded,
121
+ buildTagoBusCompletionPromptIfNeeded,
122
+ buildTagoBusFinalAnswerRepairPromptIfNeeded,
123
+ buildTagoBusFollowupPromptIfNeeded,
124
+ selectUmmayaToolChoiceOverride,
125
+ shouldWithholdAirKoreaFinalAnswer,
126
+ shouldWithholdGenericPendingFinalAnswer,
127
+ shouldWithholdTagoBusFinalAnswer,
128
+ } from './tools/_shared/toolChoiceRepair.js'
129
+ import {
130
+ buildTextToolCallFinalAnswerRepairPromptIfNeeded,
131
+ shouldWithholdTextToolCallFinalAnswer,
132
+ } from './tools/_shared/textToolCallGuard.js'
133
+ import { getAdapterToolByName } from './tools/AdapterTool/AdapterTool.js'
102
134
  import { buildQueryConfig } from './query/config.js'
103
135
  import { productionDeps, type QueryDeps } from './query/deps.js'
104
136
  import { ensureUmmayaAdapterManifest } from './ipc/bridgeSingleton.js'
@@ -679,6 +711,15 @@ async function* queryLoop(
679
711
  try {
680
712
  let streamingFallbackOccured = false
681
713
  queryCheckpoint('query_api_streaming_start')
714
+ const toolChoiceOverride = selectUmmayaToolChoiceOverride({
715
+ messages: messagesForQuery,
716
+ tools: toolUseContext.options.tools,
717
+ })
718
+ if (toolChoiceOverride) {
719
+ logForDebugging(
720
+ `UMMAYA tool-choice override: ${toolChoiceOverride.name}`,
721
+ )
722
+ }
682
723
  for await (const message of deps.callModel({
683
724
  messages: prependUserContext(messagesForQuery, userContext),
684
725
  systemPrompt: fullSystemPrompt,
@@ -694,7 +735,7 @@ async function* queryLoop(
694
735
  ...(config.gates.fastModeEnabled && {
695
736
  fastMode: appState.fastMode,
696
737
  }),
697
- toolChoice: undefined,
738
+ toolChoice: toolChoiceOverride,
698
739
  isNonInteractiveSession:
699
740
  toolUseContext.options.isNonInteractiveSession,
700
741
  fallbackModel,
@@ -715,6 +756,7 @@ async function* queryLoop(
715
756
  ),
716
757
  queryTracking,
717
758
  effortValue: appState.effortValue,
759
+ reasoningMode: appState.reasoningMode,
718
760
  advisorModel: appState.advisorModel,
719
761
  skipCacheWrite,
720
762
  agentId: toolUseContext.agentId,
@@ -820,6 +862,11 @@ async function* queryLoop(
820
862
  // tree-shaking constraint), so the collapse check is nested
821
863
  // rather than composed.
822
864
  let withheld = false
865
+ const assistantHasToolUse =
866
+ message.type === 'assistant' &&
867
+ message.message.content.some(
868
+ content => content.type === 'tool_use',
869
+ )
823
870
  if (feature('CONTEXT_COLLAPSE')) {
824
871
  if (
825
872
  contextCollapse?.isWithheldPromptTooLong(
@@ -843,6 +890,73 @@ async function* queryLoop(
843
890
  if (isWithheldMaxOutputTokens(message)) {
844
891
  withheld = true
845
892
  }
893
+ if (
894
+ message.type === 'assistant' &&
895
+ !assistantHasToolUse &&
896
+ shouldWithholdKmaAnalysisToolCallText({
897
+ messages: messagesForQuery,
898
+ candidate: message,
899
+ })
900
+ ) {
901
+ withheld = true
902
+ }
903
+ if (
904
+ message.type === 'assistant' &&
905
+ !assistantHasToolUse &&
906
+ shouldWithholdProtectedCheckToolCallText({
907
+ messages: messagesForQuery,
908
+ candidate: message,
909
+ })
910
+ ) {
911
+ withheld = true
912
+ }
913
+ if (
914
+ message.type === 'assistant' &&
915
+ !assistantHasToolUse &&
916
+ shouldWithholdTagoBusFinalAnswer({
917
+ messages: messagesForQuery,
918
+ candidate: message,
919
+ })
920
+ ) {
921
+ withheld = true
922
+ }
923
+ if (
924
+ message.type === 'assistant' &&
925
+ !assistantHasToolUse &&
926
+ shouldWithholdAirKoreaFinalAnswer({
927
+ messages: messagesForQuery,
928
+ candidate: message,
929
+ })
930
+ ) {
931
+ withheld = true
932
+ }
933
+ if (
934
+ message.type === 'assistant' &&
935
+ !assistantHasToolUse &&
936
+ shouldWithholdGenericPendingFinalAnswer({
937
+ messages: messagesForQuery,
938
+ candidate: message,
939
+ })
940
+ ) {
941
+ withheld = true
942
+ }
943
+ if (
944
+ message.type === 'assistant' &&
945
+ !assistantHasToolUse &&
946
+ shouldWithholdTextToolCallFinalAnswer({
947
+ messages: messagesForQuery,
948
+ candidate: message,
949
+ })
950
+ ) {
951
+ withheld = true
952
+ }
953
+ // Claude Code streams native tool_use blocks as visible assistant
954
+ // commits before tool execution. UMMAYA recovery/repair guards may
955
+ // withhold prose, but they must never hide the structured tool_use
956
+ // message that anchors the following tool_result.
957
+ if (assistantHasToolUse) {
958
+ withheld = false
959
+ }
846
960
  if (!withheld) {
847
961
  yield yieldMessage
848
962
  }
@@ -1287,6 +1401,220 @@ async function* queryLoop(
1287
1401
  return { reason: 'completed' }
1288
1402
  }
1289
1403
 
1404
+ const kmaAnalysisMissingToolPrompt =
1405
+ buildKmaAnalysisMissingToolPromptIfNeeded({
1406
+ messages: [...messagesForQuery, ...assistantMessages],
1407
+ })
1408
+ if (kmaAnalysisMissingToolPrompt) {
1409
+ const kmaAnalysisChartTool = getAdapterToolByName(
1410
+ 'kma_apihub_url_analysis_weather_chart_image',
1411
+ )
1412
+ let nextToolUseContext = toolUseContext
1413
+ if (
1414
+ kmaAnalysisChartTool &&
1415
+ !toolUseContext.options.tools.some(
1416
+ tool => tool.name === kmaAnalysisChartTool.name,
1417
+ )
1418
+ ) {
1419
+ nextToolUseContext = {
1420
+ ...toolUseContext,
1421
+ options: {
1422
+ ...toolUseContext.options,
1423
+ tools: [...toolUseContext.options.tools, kmaAnalysisChartTool],
1424
+ },
1425
+ }
1426
+ }
1427
+ const next: State = {
1428
+ messages: [
1429
+ ...messagesForQuery,
1430
+ ...assistantMessages,
1431
+ createUserMessage({
1432
+ content: kmaAnalysisMissingToolPrompt,
1433
+ isMeta: true,
1434
+ }),
1435
+ ],
1436
+ toolUseContext: nextToolUseContext,
1437
+ autoCompactTracking: tracking,
1438
+ maxOutputTokensRecoveryCount: 0,
1439
+ hasAttemptedReactiveCompact,
1440
+ maxOutputTokensOverride: undefined,
1441
+ pendingToolUseSummary: undefined,
1442
+ stopHookActive: true,
1443
+ turnCount,
1444
+ transition: { reason: 'stop_hook_blocking' },
1445
+ }
1446
+ state = next
1447
+ continue
1448
+ }
1449
+
1450
+ const kmaAnalysisFinalAnswerRepairPrompt =
1451
+ buildKmaAnalysisFinalAnswerRepairPromptIfNeeded({
1452
+ messages: [...messagesForQuery, ...assistantMessages],
1453
+ })
1454
+ if (kmaAnalysisFinalAnswerRepairPrompt) {
1455
+ const next: State = {
1456
+ messages: [
1457
+ ...messagesForQuery,
1458
+ ...assistantMessages,
1459
+ createUserMessage({
1460
+ content: kmaAnalysisFinalAnswerRepairPrompt,
1461
+ isMeta: true,
1462
+ }),
1463
+ ],
1464
+ toolUseContext,
1465
+ autoCompactTracking: tracking,
1466
+ maxOutputTokensRecoveryCount: 0,
1467
+ hasAttemptedReactiveCompact,
1468
+ maxOutputTokensOverride: undefined,
1469
+ pendingToolUseSummary: undefined,
1470
+ stopHookActive: true,
1471
+ turnCount,
1472
+ transition: { reason: 'stop_hook_blocking' },
1473
+ }
1474
+ state = next
1475
+ continue
1476
+ }
1477
+
1478
+ const protectedCheckFinalAnswerRepairPrompt =
1479
+ buildProtectedCheckFinalAnswerRepairPromptIfNeeded({
1480
+ messages: [...messagesForQuery, ...assistantMessages],
1481
+ })
1482
+ if (protectedCheckFinalAnswerRepairPrompt) {
1483
+ const next: State = {
1484
+ messages: [
1485
+ ...messagesForQuery,
1486
+ ...assistantMessages,
1487
+ createUserMessage({
1488
+ content: protectedCheckFinalAnswerRepairPrompt,
1489
+ isMeta: true,
1490
+ }),
1491
+ ],
1492
+ toolUseContext,
1493
+ autoCompactTracking: tracking,
1494
+ maxOutputTokensRecoveryCount: 0,
1495
+ hasAttemptedReactiveCompact,
1496
+ maxOutputTokensOverride: undefined,
1497
+ pendingToolUseSummary: undefined,
1498
+ stopHookActive: true,
1499
+ turnCount,
1500
+ transition: { reason: 'stop_hook_blocking' },
1501
+ }
1502
+ state = next
1503
+ continue
1504
+ }
1505
+
1506
+ const airKoreaFinalAnswerRepairPrompt =
1507
+ buildAirKoreaFinalAnswerRepairPromptIfNeeded({
1508
+ messages: [...messagesForQuery, ...assistantMessages],
1509
+ })
1510
+ if (airKoreaFinalAnswerRepairPrompt) {
1511
+ const next: State = {
1512
+ messages: [
1513
+ ...messagesForQuery,
1514
+ ...assistantMessages,
1515
+ createUserMessage({
1516
+ content: airKoreaFinalAnswerRepairPrompt,
1517
+ isMeta: true,
1518
+ }),
1519
+ ],
1520
+ toolUseContext,
1521
+ autoCompactTracking: tracking,
1522
+ maxOutputTokensRecoveryCount: 0,
1523
+ hasAttemptedReactiveCompact,
1524
+ maxOutputTokensOverride: undefined,
1525
+ pendingToolUseSummary: undefined,
1526
+ stopHookActive: true,
1527
+ turnCount,
1528
+ transition: { reason: 'stop_hook_blocking' },
1529
+ }
1530
+ state = next
1531
+ continue
1532
+ }
1533
+
1534
+ const tagoBusFinalAnswerRepairPrompt =
1535
+ buildTagoBusFinalAnswerRepairPromptIfNeeded({
1536
+ messages: [...messagesForQuery, ...assistantMessages],
1537
+ })
1538
+ if (tagoBusFinalAnswerRepairPrompt) {
1539
+ const next: State = {
1540
+ messages: [
1541
+ ...messagesForQuery,
1542
+ ...assistantMessages,
1543
+ createUserMessage({
1544
+ content: tagoBusFinalAnswerRepairPrompt,
1545
+ isMeta: true,
1546
+ }),
1547
+ ],
1548
+ toolUseContext,
1549
+ autoCompactTracking: tracking,
1550
+ maxOutputTokensRecoveryCount: 0,
1551
+ hasAttemptedReactiveCompact,
1552
+ maxOutputTokensOverride: undefined,
1553
+ pendingToolUseSummary: undefined,
1554
+ stopHookActive: true,
1555
+ turnCount,
1556
+ transition: { reason: 'stop_hook_blocking' },
1557
+ }
1558
+ state = next
1559
+ continue
1560
+ }
1561
+
1562
+ const textToolCallFinalAnswerRepairPrompt =
1563
+ buildTextToolCallFinalAnswerRepairPromptIfNeeded({
1564
+ messages: [...messagesForQuery, ...assistantMessages],
1565
+ })
1566
+ if (textToolCallFinalAnswerRepairPrompt) {
1567
+ const next: State = {
1568
+ messages: [
1569
+ ...messagesForQuery,
1570
+ ...assistantMessages,
1571
+ createUserMessage({
1572
+ content: textToolCallFinalAnswerRepairPrompt,
1573
+ isMeta: true,
1574
+ }),
1575
+ ],
1576
+ toolUseContext,
1577
+ autoCompactTracking: tracking,
1578
+ maxOutputTokensRecoveryCount: 0,
1579
+ hasAttemptedReactiveCompact,
1580
+ maxOutputTokensOverride: undefined,
1581
+ pendingToolUseSummary: undefined,
1582
+ stopHookActive: true,
1583
+ turnCount,
1584
+ transition: { reason: 'stop_hook_blocking' },
1585
+ }
1586
+ state = next
1587
+ continue
1588
+ }
1589
+
1590
+ const genericPendingFinalAnswerRepairPrompt =
1591
+ buildGenericPendingFinalAnswerRepairPromptIfNeeded({
1592
+ messages: [...messagesForQuery, ...assistantMessages],
1593
+ })
1594
+ if (genericPendingFinalAnswerRepairPrompt) {
1595
+ const next: State = {
1596
+ messages: [
1597
+ ...messagesForQuery,
1598
+ ...assistantMessages,
1599
+ createUserMessage({
1600
+ content: genericPendingFinalAnswerRepairPrompt,
1601
+ isMeta: true,
1602
+ }),
1603
+ ],
1604
+ toolUseContext,
1605
+ autoCompactTracking: tracking,
1606
+ maxOutputTokensRecoveryCount: 0,
1607
+ hasAttemptedReactiveCompact,
1608
+ maxOutputTokensOverride: undefined,
1609
+ pendingToolUseSummary: undefined,
1610
+ stopHookActive: true,
1611
+ turnCount,
1612
+ transition: { reason: 'stop_hook_blocking' },
1613
+ }
1614
+ state = next
1615
+ continue
1616
+ }
1617
+
1290
1618
  const stopHookResult = yield* handleStopHooks(
1291
1619
  messagesForQuery,
1292
1620
  assistantMessages,
@@ -1385,7 +1713,6 @@ async function* queryLoop(
1385
1713
 
1386
1714
  queryCheckpoint('query_tool_execution_start')
1387
1715
 
1388
-
1389
1716
  if (streamingToolExecutor) {
1390
1717
  logEvent('tengu_streaming_tool_execution_used', {
1391
1718
  tool_count: toolUseBlocks.length,
@@ -1693,6 +2020,144 @@ async function* queryLoop(
1693
2020
  }
1694
2021
  }
1695
2022
 
2023
+ const nmcAedMessages = [...messagesForQuery, ...assistantMessages, ...toolResults]
2024
+ const nmcAedTool = getAdapterToolByName('nmc_aed_site_locate')
2025
+ const nmcRegionTool = getAdapterToolByName('kakao_coord_to_region')
2026
+ const nmcAedAvailableToolNames = new Set(
2027
+ updatedToolUseContext.options.tools.map(tool => tool.name),
2028
+ )
2029
+ if (nmcAedTool) {
2030
+ nmcAedAvailableToolNames.add(nmcAedTool.name)
2031
+ }
2032
+ if (nmcRegionTool) {
2033
+ nmcAedAvailableToolNames.add(nmcRegionTool.name)
2034
+ }
2035
+ const missingNmcHelperTools = [nmcAedTool, nmcRegionTool].filter(
2036
+ (tool): tool is NonNullable<ReturnType<typeof getAdapterToolByName>> =>
2037
+ Boolean(tool) &&
2038
+ !updatedToolUseContext.options.tools.some(existing => existing.name === tool.name),
2039
+ )
2040
+ if (missingNmcHelperTools.length > 0) {
2041
+ updatedToolUseContext = {
2042
+ ...updatedToolUseContext,
2043
+ options: {
2044
+ ...updatedToolUseContext.options,
2045
+ tools: [...updatedToolUseContext.options.tools, ...missingNmcHelperTools],
2046
+ },
2047
+ }
2048
+ }
2049
+ const nmcAedFollowupPrompt = buildNmcAedFollowupPromptIfNeeded({
2050
+ messages: nmcAedMessages,
2051
+ availableToolNames: nmcAedAvailableToolNames,
2052
+ })
2053
+ if (nmcAedFollowupPrompt) {
2054
+ toolResults.push(
2055
+ createUserMessage({
2056
+ content: nmcAedFollowupPrompt,
2057
+ isMeta: true,
2058
+ }),
2059
+ )
2060
+ } else {
2061
+ const tagoBusMessages = [...messagesForQuery, ...assistantMessages, ...toolResults]
2062
+ const tagoBusTools = [
2063
+ getAdapterToolByName('tago_bus_route_search'),
2064
+ getAdapterToolByName('tago_bus_route_station_search'),
2065
+ getAdapterToolByName('tago_bus_arrival_search'),
2066
+ ].filter(
2067
+ (tool): tool is NonNullable<ReturnType<typeof getAdapterToolByName>> =>
2068
+ Boolean(tool),
2069
+ )
2070
+ const tagoBusAvailableToolNames = new Set(
2071
+ updatedToolUseContext.options.tools.map(tool => tool.name),
2072
+ )
2073
+ for (const tool of tagoBusTools) {
2074
+ tagoBusAvailableToolNames.add(tool.name)
2075
+ }
2076
+ const tagoBusFollowupPrompt = buildTagoBusFollowupPromptIfNeeded({
2077
+ messages: tagoBusMessages,
2078
+ availableToolNames: tagoBusAvailableToolNames,
2079
+ })
2080
+ if (tagoBusFollowupPrompt) {
2081
+ const existingToolNames = new Set(
2082
+ updatedToolUseContext.options.tools.map(tool => tool.name),
2083
+ )
2084
+ const missingTagoBusTools = tagoBusTools.filter(
2085
+ tool => !existingToolNames.has(tool.name),
2086
+ )
2087
+ if (missingTagoBusTools.length > 0) {
2088
+ updatedToolUseContext = {
2089
+ ...updatedToolUseContext,
2090
+ options: {
2091
+ ...updatedToolUseContext.options,
2092
+ tools: [...updatedToolUseContext.options.tools, ...missingTagoBusTools],
2093
+ },
2094
+ }
2095
+ }
2096
+ toolResults.push(
2097
+ createUserMessage({
2098
+ content: tagoBusFollowupPrompt,
2099
+ isMeta: true,
2100
+ }),
2101
+ )
2102
+ } else {
2103
+ const nmcAedCompletionPrompt = buildNmcAedCompletionPromptIfNeeded({
2104
+ messages: [...messagesForQuery, ...assistantMessages, ...toolResults],
2105
+ })
2106
+ if (nmcAedCompletionPrompt) {
2107
+ toolResults.push(
2108
+ createUserMessage({
2109
+ content: nmcAedCompletionPrompt,
2110
+ isMeta: true,
2111
+ }),
2112
+ )
2113
+ }
2114
+ const tagoBusCompletionPrompt = buildTagoBusCompletionPromptIfNeeded({
2115
+ messages: [...messagesForQuery, ...assistantMessages, ...toolResults],
2116
+ })
2117
+ if (tagoBusCompletionPrompt) {
2118
+ toolResults.push(
2119
+ createUserMessage({
2120
+ content: tagoBusCompletionPrompt,
2121
+ isMeta: true,
2122
+ }),
2123
+ )
2124
+ }
2125
+ const protectedCheckCompletionPrompt = buildProtectedCheckCompletionPromptIfNeeded({
2126
+ messages: [...messagesForQuery, ...assistantMessages, ...toolResults],
2127
+ })
2128
+ if (protectedCheckCompletionPrompt) {
2129
+ toolResults.push(
2130
+ createUserMessage({
2131
+ content: protectedCheckCompletionPrompt,
2132
+ isMeta: true,
2133
+ }),
2134
+ )
2135
+ }
2136
+ const kmaAnalysisCompletionPrompt = buildKmaAnalysisCompletionPromptIfNeeded({
2137
+ messages: [...messagesForQuery, ...assistantMessages, ...toolResults],
2138
+ })
2139
+ if (kmaAnalysisCompletionPrompt) {
2140
+ toolResults.push(
2141
+ createUserMessage({
2142
+ content: kmaAnalysisCompletionPrompt,
2143
+ isMeta: true,
2144
+ }),
2145
+ )
2146
+ }
2147
+ const airKoreaCompletionPrompt = buildAirKoreaCompletionPromptIfNeeded({
2148
+ messages: [...messagesForQuery, ...assistantMessages, ...toolResults],
2149
+ })
2150
+ if (airKoreaCompletionPrompt) {
2151
+ toolResults.push(
2152
+ createUserMessage({
2153
+ content: airKoreaCompletionPrompt,
2154
+ isMeta: true,
2155
+ }),
2156
+ )
2157
+ }
2158
+ }
2159
+ }
2160
+
1696
2161
  const toolUseContextWithQueryTracking = {
1697
2162
  ...updatedToolUseContext,
1698
2163
  queryTracking,
@@ -2671,7 +2671,7 @@ export function REPL({
2671
2671
  }
2672
2672
  }
2673
2673
 
2674
- // Mark onboarding as complete when any user message is sent to Claude
2674
+ // Mark onboarding as complete when any user message is sent to UMMAYA.
2675
2675
  void maybeMarkProjectOnboardingComplete();
2676
2676
 
2677
2677
  // Extract a session title from the first real user message. One-shot
@@ -3932,7 +3932,7 @@ export function REPL({
3932
3932
  // Use ref to get current dialog state, avoiding stale closure
3933
3933
  focusedInputDialogRef.current === undefined && idleTimeSinceResponse >= getGlobalConfig().messageIdleNotifThresholdMs) {
3934
3934
  void sendNotification({
3935
- message: 'Claude is waiting for your input',
3935
+ message: 'UMMAYA is waiting for your input',
3936
3936
  notificationType: 'idle_prompt'
3937
3937
  }, terminal);
3938
3938
  }
@@ -4893,7 +4893,7 @@ export function REPL({
4893
4893
 
4894
4894
  {!toolJSX?.shouldHidePromptInput && !focusedInputDialog && !isExiting && !disabled && !cursor && <>
4895
4895
  {autoRunIssueReason && <AutoRunIssueNotification onRun={handleAutoRunIssue} onCancel={handleCancelAutoRunIssue} reason={getAutoRunIssueReasonText(autoRunIssueReason)} />}
4896
- {postCompactSurvey.state !== 'closed' ? <FeedbackSurvey state={postCompactSurvey.state} lastResponse={postCompactSurvey.lastResponse} handleSelect={postCompactSurvey.handleSelect} inputValue={inputValue} setInputValue={setInputValue} onRequestFeedback={handleSurveyRequestFeedback} /> : memorySurvey.state !== 'closed' ? <FeedbackSurvey state={memorySurvey.state} lastResponse={memorySurvey.lastResponse} handleSelect={memorySurvey.handleSelect} handleTranscriptSelect={memorySurvey.handleTranscriptSelect} inputValue={inputValue} setInputValue={setInputValue} onRequestFeedback={handleSurveyRequestFeedback} message="How well did Claude use its memory? (optional)" /> : <FeedbackSurvey state={feedbackSurvey.state} lastResponse={feedbackSurvey.lastResponse} handleSelect={feedbackSurvey.handleSelect} handleTranscriptSelect={feedbackSurvey.handleTranscriptSelect} inputValue={inputValue} setInputValue={setInputValue} onRequestFeedback={didAutoRunIssueRef.current ? undefined : handleSurveyRequestFeedback} />}
4896
+ {postCompactSurvey.state !== 'closed' ? <FeedbackSurvey state={postCompactSurvey.state} lastResponse={postCompactSurvey.lastResponse} handleSelect={postCompactSurvey.handleSelect} inputValue={inputValue} setInputValue={setInputValue} onRequestFeedback={handleSurveyRequestFeedback} /> : memorySurvey.state !== 'closed' ? <FeedbackSurvey state={memorySurvey.state} lastResponse={memorySurvey.lastResponse} handleSelect={memorySurvey.handleSelect} handleTranscriptSelect={memorySurvey.handleTranscriptSelect} inputValue={inputValue} setInputValue={setInputValue} onRequestFeedback={handleSurveyRequestFeedback} message="How well did UMMAYA use its memory? (optional)" /> : <FeedbackSurvey state={feedbackSurvey.state} lastResponse={feedbackSurvey.lastResponse} handleSelect={feedbackSurvey.handleSelect} handleTranscriptSelect={feedbackSurvey.handleTranscriptSelect} inputValue={inputValue} setInputValue={setInputValue} onRequestFeedback={didAutoRunIssueRef.current ? undefined : handleSurveyRequestFeedback} />}
4897
4897
  {/* Frustration-triggered transcript sharing prompt */}
4898
4898
  {frustrationDetection.state !== 'closed' && <FeedbackSurvey state={frustrationDetection.state} lastResponse={null} handleSelect={() => {}} handleTranscriptSelect={frustrationDetection.handleTranscriptSelect} inputValue={inputValue} setInputValue={setInputValue} />}
4899
4899
  {/* Skill improvement survey - appears when improvements detected (ant-only) */}