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.
- package/README.md +2 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/prompts/manifest.yaml +2 -2
- package/prompts/session_guidance_v1.md +3 -1
- package/prompts/system_v1.md +8 -7
- package/pyproject.toml +2 -7
- package/src/ummaya/context/builder.py +17 -11
- package/src/ummaya/engine/engine.py +27 -7
- package/src/ummaya/engine/query.py +20 -0
- package/src/ummaya/evidence/__init__.py +25 -0
- package/src/ummaya/evidence/__main__.py +7 -0
- package/src/ummaya/evidence/models.py +58 -0
- package/src/ummaya/evidence/runner.py +308 -0
- package/src/ummaya/evidence/task_registry.py +264 -0
- package/src/ummaya/ipc/frame_schema.py +47 -0
- package/src/ummaya/ipc/stdio.py +1349 -90
- package/src/ummaya/llm/client.py +132 -56
- package/src/ummaya/llm/reasoning.py +84 -0
- package/src/ummaya/tools/discovery_bridge.py +17 -1
- package/src/ummaya/tools/executor.py +32 -12
- package/src/ummaya/tools/geocoding/kakao_client.py +1 -2
- package/src/ummaya/tools/kma/apihub_catalog.py +984 -1
- package/src/ummaya/tools/kma/apihub_structured_adapter.py +86 -6
- package/src/ummaya/tools/kma/apihub_url_adapter.py +593 -0
- package/src/ummaya/tools/kma/apihub_url_catalog.py +296 -0
- package/src/ummaya/tools/location_adapters.py +8 -6
- package/src/ummaya/tools/manifest_metadata.py +16 -3
- package/src/ummaya/tools/mvp_surface.py +2 -2
- package/src/ummaya/tools/nmc/emergency_search.py +8 -6
- package/src/ummaya/tools/register_all.py +9 -0
- package/src/ummaya/tools/resolve_location.py +4 -4
- package/src/ummaya/tools/search.py +664 -18
- package/src/ummaya/tools/verified_data_go_kr/_manifest.py +115 -25
- package/src/ummaya/tools/verified_data_go_kr/airkorea_air_quality.py +109 -4
- package/src/ummaya/tools/verified_data_go_kr/nmc_aed_site.py +108 -2
- package/src/ummaya/tools/verified_data_go_kr/pps_bid_public_info.py +174 -9
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_arrival.py +66 -3
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_location.py +12 -2
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_route.py +8 -2
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_route_station.py +114 -0
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_station.py +14 -3
- package/src/ummaya/tools/verify_canonical_map.py +21 -0
- package/tui/package.json +1 -2
- package/tui/src/QueryEngine.ts +4 -0
- package/tui/src/cli/handlers/auth.ts +1 -1
- package/tui/src/cli/handlers/mcp.tsx +3 -3
- package/tui/src/cli/print.ts +69 -18
- package/tui/src/cli/update.ts +13 -13
- package/tui/src/commands/copy/index.ts +1 -1
- package/tui/src/commands/cost/cost.ts +2 -2
- package/tui/src/commands/init-verifiers.ts +5 -5
- package/tui/src/commands/init.ts +30 -30
- package/tui/src/commands/insights.ts +43 -43
- package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
- package/tui/src/commands/install-github-app/setupGitHubActions.ts +3 -3
- package/tui/src/commands/install.tsx +5 -5
- package/tui/src/commands/mcp/addCommand.ts +5 -5
- package/tui/src/commands/mcp/xaaIdpCommand.ts +2 -2
- package/tui/src/commands/plugin/ManageMarketplaces.tsx +2 -2
- package/tui/src/commands/reasoning/index.ts +13 -0
- package/tui/src/commands/reasoning/reasoning.tsx +177 -0
- package/tui/src/commands/thinkback/thinkback.tsx +3 -3
- package/tui/src/commands.ts +2 -0
- package/tui/src/components/Messages.tsx +2 -1
- package/tui/src/components/Spinner.tsx +2 -2
- package/tui/src/components/design-system/LoadingState.tsx +2 -2
- package/tui/src/ipc/codec.ts +26 -0
- package/tui/src/ipc/frames.generated.ts +398 -303
- package/tui/src/ipc/llmClient.ts +130 -51
- package/tui/src/ipc/llmTypes.ts +16 -1
- package/tui/src/ipc/schema/frame.schema.json +1 -3475
- package/tui/src/main.tsx +3 -0
- package/tui/src/query.ts +467 -2
- package/tui/src/screens/REPL.tsx +3 -3
- package/tui/src/services/api/claude.ts +54 -25
- package/tui/src/services/api/client.ts +33 -12
- package/tui/src/services/api/ummaya.ts +70 -16
- package/tui/src/skills/bundled/stuck.ts +12 -12
- package/tui/src/state/AppStateStore.ts +7 -0
- package/tui/src/tools/AdapterTool/AdapterTool.ts +590 -7
- package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +43 -17
- package/tui/src/tools/LookupPrimitive/prompt.ts +7 -6
- package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +40 -19
- package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +25 -9
- package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +25 -9
- package/tui/src/tools/_shared/citizenUserText.ts +49 -0
- package/tui/src/tools/_shared/directPublicDataGuard.ts +362 -0
- package/tui/src/tools/_shared/kmaAnalysisGuard.ts +197 -0
- package/tui/src/tools/_shared/kmaAviationGuard.ts +70 -0
- package/tui/src/tools/_shared/locationInputRepair.ts +112 -0
- package/tui/src/tools/_shared/nmcAedGuard.ts +234 -0
- package/tui/src/tools/_shared/protectedCheckGuard.ts +207 -0
- package/tui/src/tools/_shared/rootPrimitiveInput.ts +67 -0
- package/tui/src/tools/_shared/textToolCallGuard.ts +91 -0
- package/tui/src/tools/_shared/toolChoiceRepair.ts +866 -0
- package/tui/src/utils/attachments.ts +1 -1
- package/tui/src/utils/kExaoneReasoning.ts +138 -0
- package/tui/src/utils/messages.ts +1 -0
- package/tui/src/utils/multiToolLayout.ts +13 -0
- package/tui/src/utils/processUserInput/processSlashCommand.tsx +2 -2
- package/tui/src/utils/processUserInput/processUserInput.ts +26 -0
- package/tui/src/utils/settings/applySettingsChange.ts +4 -0
- package/tui/src/utils/settings/types.ts +9 -3
- package/tui/src/utils/stats.ts +1 -1
- package/uv.lock +1 -15
- package/assets/copilot-gate-logo.svg +0 -58
- package/assets/govon-logo.svg +0 -40
- package/src/ummaya/eval/__init__.py +0 -5
- package/src/ummaya/eval/retrieval.py +0 -713
- package/tui/src/utils/messageStream.ts +0 -186
|
@@ -14,6 +14,13 @@ import {
|
|
|
14
14
|
import { getOrCreateUmmayaBridge } from '../../ipc/bridgeSingleton.js'
|
|
15
15
|
import { getOrCreatePendingCallRegistry } from '../../ipc/pendingCallSingleton.js'
|
|
16
16
|
import { dispatchPrimitive } from '../_shared/dispatchPrimitive.js'
|
|
17
|
+
import { validateKmaAviationToolChoice } from '../_shared/kmaAviationGuard.js'
|
|
18
|
+
import { validateKmaAnalysisToolChoice } from '../_shared/kmaAnalysisGuard.js'
|
|
19
|
+
import { validateNmcAedToolChoice } from '../_shared/nmcAedGuard.js'
|
|
20
|
+
import {
|
|
21
|
+
normalizeDirectPublicDataToolInput,
|
|
22
|
+
validateDirectPublicDataToolChoice,
|
|
23
|
+
} from '../_shared/directPublicDataGuard.js'
|
|
17
24
|
import { LookupPrimitive } from '../LookupPrimitive/LookupPrimitive.js'
|
|
18
25
|
import { ResolveLocationPrimitive } from '../ResolveLocationPrimitive/ResolveLocationPrimitive.js'
|
|
19
26
|
import { SubmitPrimitive } from '../SubmitPrimitive/SubmitPrimitive.js'
|
|
@@ -24,6 +31,72 @@ type AdapterPrimitive = 'find' | 'locate' | 'send' | 'check'
|
|
|
24
31
|
type InputSchema = z.ZodType<{ [key: string]: unknown }>
|
|
25
32
|
|
|
26
33
|
const ROOT_PRIMITIVE_TOOL_NAMES = new Set(['locate', 'find', 'check', 'send'])
|
|
34
|
+
const KMA_URL_AIR_TOOL_NAMES = new Set([
|
|
35
|
+
'kma_apihub_url_air_amos_minute',
|
|
36
|
+
'kma_apihub_url_air_metar_decoded',
|
|
37
|
+
])
|
|
38
|
+
const KMA_ANALYSIS_TOOL_NAMES = new Set([
|
|
39
|
+
'kma_apihub_url_high_resolution_grid_point',
|
|
40
|
+
'kma_apihub_url_aws_objective_analysis_grid',
|
|
41
|
+
'kma_apihub_url_analysis_weather_chart_image',
|
|
42
|
+
])
|
|
43
|
+
const TAGO_BUS_TOOL_NAMES = new Set([
|
|
44
|
+
'tago_bus_station_search',
|
|
45
|
+
'tago_bus_arrival_search',
|
|
46
|
+
'tago_bus_route_search',
|
|
47
|
+
'tago_bus_route_station_search',
|
|
48
|
+
'tago_bus_location_search',
|
|
49
|
+
])
|
|
50
|
+
const KMA_GIMHAE_AIRPORT_RE = /(김해공항|gimhae|rkpk)/iu
|
|
51
|
+
const KMA_GIMPO_AIRPORT_RE = /(김포공항|gimpo|rkss)/iu
|
|
52
|
+
const KMA_AIRPORT_NAME_RE = /(공항|\bairport\b|\brk[a-z]{2}\b|station\s*\d{2,3})/iu
|
|
53
|
+
const KMA_AIRPORT_AVIATION_RE =
|
|
54
|
+
/(amos|metar|speci|rvr|항공기상|공항기상|활주로|runway|aviation|비행기|항공편|비행편|이륙|착륙|결항|지연|운항|뜰\s*만|뜨나|뜰\s*수|flight|take\s*off|landing|delay|cancel)/iu
|
|
55
|
+
const KMA_RUNWAY_AREA_RE =
|
|
56
|
+
/(amos|활주로|rvr|runway|시정|visibility|공항기상관측|매분)/iu
|
|
57
|
+
const KMA_ANALYSIS_DATA_RE =
|
|
58
|
+
/(분석자료|이미\s*분석|고해상도\s*격자|객관분석|aws\s*객관|지도\s*자료|일기도|분석일기도|비구름|바람\s*흐름|synoptic|weather\s*chart|objective\s*analysis|high[-\s]?resolution|grid)/iu
|
|
59
|
+
const KMA_ANALYSIS_MAP_RE =
|
|
60
|
+
/(일기도|분석일기도|지도\s*자료|비구름|바람\s*흐름|synoptic|weather\s*chart)/iu
|
|
61
|
+
const KMA_ANALYSIS_POINT_RE =
|
|
62
|
+
/(주변|근처|특정지점|좌표|위도|경도|\blat\b|\blon\b|공항\s*주변)/iu
|
|
63
|
+
const KMA_LIFESTYLE_WEATHER_RE =
|
|
64
|
+
/(날씨|현재\s*기상|실황|관측|예보|기온|습도|풍속|지금\s*비|비\s*(와|오|올|내리)|우산|강수|소나기|산책|퇴근|current\s+weather|forecast|rain|umbrella|precipitation|temperature)/iu
|
|
65
|
+
const KMA_LIFESTYLE_WEATHER_TOOL_NAMES = new Set([
|
|
66
|
+
'kma_current_observation',
|
|
67
|
+
'kma_ultra_short_term_forecast',
|
|
68
|
+
'kma_short_term_forecast',
|
|
69
|
+
])
|
|
70
|
+
const HIRA_MEDICAL_DETAIL_RE =
|
|
71
|
+
/((병원|의료기관|의원).*(상세|진료과|진료과목|진료시간|주차)|(상세|진료시간|주차|응급실).*(병원|의료기관|의원)|ykiho|detail)/iu
|
|
72
|
+
const MOIS_EMERGENCY_CALL_BOX_RE =
|
|
73
|
+
/(안전\s*비상벨|비상벨|긴급\s*신고함|긴급신고함|방범벨|emergency\s+call\s+box)/iu
|
|
74
|
+
const GYERYONG_ASSISTIVE_CHARGER_RE =
|
|
75
|
+
/((전동보장구|전동\s*휠체어|보장구|장애인).*(충전|충전소|충전장소)|(충전|충전소|충전장소).*(전동보장구|전동\s*휠체어|보장구|장애인)|계룡시?.*(충전소|충전\s*장소))/iu
|
|
76
|
+
const MOF_OCEAN_WATER_QUALITY_RE =
|
|
77
|
+
/(해양\s*수질|해양수질|수질\s*자동\s*측정|용존산소|\bpH\b|water\s+quality|ocean\s+water)/iu
|
|
78
|
+
const PPS_SHOPPING_RE = /(종합\s*쇼핑몰|쇼핑몰|계약\s*물품|물품\s*조회|shopping\s*mall)/iu
|
|
79
|
+
const PPS_BID_RE = /(입찰|나라장터|조달청|\bbid\b|procurement|tender)/iu
|
|
80
|
+
const PROTECTED_QUERY_RE =
|
|
81
|
+
/(본인확인|인증|간편인증|모바일\s*(?:신분증|id)|mobile\s*id|마이데이터|mydata|증명원|소득금액증명|소득금액증명원|주민등록등본|민원|발급)/iu
|
|
82
|
+
const PROTECTED_MOBILE_ID_RE = /(mobile\s*id|모바일\s*(?:신분증|id)|mobile_id)/iu
|
|
83
|
+
const PROTECTED_SIMPLE_AUTH_RE =
|
|
84
|
+
/(simple_auth|간편인증|ganpyeon|소득금액증명|증명원|민원|발급)/iu
|
|
85
|
+
const PROTECTED_MYDATA_RE = /(mydata|마이데이터)/iu
|
|
86
|
+
const PROTECTED_CHECK_TOOL_NAMES = [
|
|
87
|
+
'mock_verify_module_simple_auth',
|
|
88
|
+
'mock_verify_ganpyeon_injeung',
|
|
89
|
+
'mock_verify_mobile_id',
|
|
90
|
+
'mock_verify_mydata',
|
|
91
|
+
] as const
|
|
92
|
+
const TAGO_BUS_RE =
|
|
93
|
+
/(버스|시내버스|정류장|정류소|노선|도착|언제\s*와|몇\s*분|bus|route|arrival|station)/iu
|
|
94
|
+
const AED_REQUEST_RE = /(aed|자동심장|심장충격|제세동)/iu
|
|
95
|
+
const EMERGENCY_REQUEST_RE = /(응급|응급실|\ber\b|emergency)/iu
|
|
96
|
+
const MEDICAL_COLLAPSE_RE =
|
|
97
|
+
/(사람이\s*쓰러|쓰러졌|쓰러져|의식\s*잃|의식을\s*잃|심정지|호흡이\s*없|숨을\s*안|collapsed|unconscious|cardiac\s*arrest)/iu
|
|
98
|
+
const TRAFFIC_HAZARD_RE =
|
|
99
|
+
/(교통사고|사고\s*위험|사고다발|위험\s*(구간|도로|지점)|어린이보호구역|보호구역|도로\s*구간|accident|hazard|hotspot)/iu
|
|
27
100
|
|
|
28
101
|
const fallbackInputSchema = z.object({}).passthrough() as InputSchema
|
|
29
102
|
|
|
@@ -212,6 +285,23 @@ function rootInputFor(entry: AdapterManifestEntry, input: Record<string, unknown
|
|
|
212
285
|
}
|
|
213
286
|
}
|
|
214
287
|
|
|
288
|
+
function validateAdapterContractInput(
|
|
289
|
+
toolId: string,
|
|
290
|
+
input: Record<string, unknown>,
|
|
291
|
+
) {
|
|
292
|
+
if (toolId !== 'kma_apihub_url_analysis_weather_chart_image') return undefined
|
|
293
|
+
const analTime = input.anal_time
|
|
294
|
+
if (typeof analTime === 'string' && /^\d{12}$/u.test(analTime)) return undefined
|
|
295
|
+
return {
|
|
296
|
+
result: false as const,
|
|
297
|
+
message:
|
|
298
|
+
'KMA analysis weather-chart schema mismatch: anal_time is required as UTC YYYYMMDDHHMM. ' +
|
|
299
|
+
"Use a 12-digit official analysis time with minutes, for example '202605281200', not a 10-digit KST hour. " +
|
|
300
|
+
'If the citizen asks for now/today, choose the latest completed official UTC analysis slot and report upstream failure directly if APIHub has no chart.',
|
|
301
|
+
errorCode: 1,
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
215
305
|
export function isAdapterToolName(name: string): boolean {
|
|
216
306
|
return resolveAdapter(name) !== undefined
|
|
217
307
|
}
|
|
@@ -236,6 +326,7 @@ function searchTokens(text: string): string[] {
|
|
|
236
326
|
function expandedQueryTokens(query: string): Set<string> {
|
|
237
327
|
const tokens = new Set(searchTokens(query))
|
|
238
328
|
const compact = query.toLowerCase()
|
|
329
|
+
const airportAviationQuery = isAirportAviationQuery(query)
|
|
239
330
|
if (/[날씨기상비강수기온습도풍속예보관측실황]/u.test(compact)) {
|
|
240
331
|
for (const token of [
|
|
241
332
|
'날씨',
|
|
@@ -251,11 +342,22 @@ function expandedQueryTokens(query: string): Set<string> {
|
|
|
251
342
|
'precipitation',
|
|
252
343
|
'humidity',
|
|
253
344
|
'wind',
|
|
345
|
+
'kma',
|
|
346
|
+
'초단기실황',
|
|
347
|
+
'초단기예보',
|
|
348
|
+
'단기예보',
|
|
349
|
+
'우산',
|
|
350
|
+
'nx',
|
|
351
|
+
'ny',
|
|
352
|
+
'base_date',
|
|
353
|
+
'base_time',
|
|
254
354
|
]) {
|
|
255
355
|
tokens.add(token)
|
|
256
356
|
}
|
|
257
357
|
}
|
|
258
|
-
|
|
358
|
+
const medicalEmergencyQuery = isMedicalEmergencyQuery(query)
|
|
359
|
+
const collapseOrAedQuery = isCollapseOrAedQuery(query)
|
|
360
|
+
if (EMERGENCY_REQUEST_RE.test(compact) && medicalEmergencyQuery) {
|
|
259
361
|
for (const token of [
|
|
260
362
|
'응급',
|
|
261
363
|
'응급실',
|
|
@@ -272,6 +374,30 @@ function expandedQueryTokens(query: string): Set<string> {
|
|
|
272
374
|
tokens.add(token)
|
|
273
375
|
}
|
|
274
376
|
}
|
|
377
|
+
if (collapseOrAedQuery) {
|
|
378
|
+
for (const token of [
|
|
379
|
+
'응급',
|
|
380
|
+
'응급실',
|
|
381
|
+
'응급의료',
|
|
382
|
+
'응급의료센터',
|
|
383
|
+
'aed',
|
|
384
|
+
'자동심장충격기',
|
|
385
|
+
'자동제세동기',
|
|
386
|
+
'심장충격기',
|
|
387
|
+
'응급처치',
|
|
388
|
+
'심정지',
|
|
389
|
+
'의식불명',
|
|
390
|
+
'emergency',
|
|
391
|
+
'room',
|
|
392
|
+
'er',
|
|
393
|
+
'defibrillator',
|
|
394
|
+
'cardiac',
|
|
395
|
+
'arrest',
|
|
396
|
+
'nmc',
|
|
397
|
+
]) {
|
|
398
|
+
tokens.add(token)
|
|
399
|
+
}
|
|
400
|
+
}
|
|
275
401
|
if (/(병원|의료|진료|약국|hospital|clinic|medical)/u.test(compact)) {
|
|
276
402
|
for (const token of [
|
|
277
403
|
'병원',
|
|
@@ -288,7 +414,134 @@ function expandedQueryTokens(query: string): Set<string> {
|
|
|
288
414
|
tokens.add(token)
|
|
289
415
|
}
|
|
290
416
|
}
|
|
291
|
-
if (
|
|
417
|
+
if (HIRA_MEDICAL_DETAIL_RE.test(query)) {
|
|
418
|
+
for (const token of [
|
|
419
|
+
'상세정보',
|
|
420
|
+
'진료과',
|
|
421
|
+
'진료과목',
|
|
422
|
+
'진료시간',
|
|
423
|
+
'주차',
|
|
424
|
+
'요양기호',
|
|
425
|
+
'ykiho',
|
|
426
|
+
'hira',
|
|
427
|
+
'detail',
|
|
428
|
+
'specialty',
|
|
429
|
+
]) {
|
|
430
|
+
tokens.add(token)
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (MOIS_EMERGENCY_CALL_BOX_RE.test(query)) {
|
|
434
|
+
for (const token of [
|
|
435
|
+
'안전비상벨',
|
|
436
|
+
'비상벨',
|
|
437
|
+
'긴급신고함',
|
|
438
|
+
'방범',
|
|
439
|
+
'행정안전부',
|
|
440
|
+
'mois',
|
|
441
|
+
'emergency',
|
|
442
|
+
'call',
|
|
443
|
+
'box',
|
|
444
|
+
]) {
|
|
445
|
+
tokens.add(token)
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (GYERYONG_ASSISTIVE_CHARGER_RE.test(query)) {
|
|
449
|
+
for (const token of [
|
|
450
|
+
'계룡시',
|
|
451
|
+
'전동보장구',
|
|
452
|
+
'전동휠체어',
|
|
453
|
+
'보장구',
|
|
454
|
+
'장애인',
|
|
455
|
+
'충전소',
|
|
456
|
+
'충전장소',
|
|
457
|
+
'accessibility',
|
|
458
|
+
'charger',
|
|
459
|
+
]) {
|
|
460
|
+
tokens.add(token)
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (MOF_OCEAN_WATER_QUALITY_RE.test(query)) {
|
|
464
|
+
for (const token of [
|
|
465
|
+
'해양수산부',
|
|
466
|
+
'해양수질',
|
|
467
|
+
'수질자동측정망',
|
|
468
|
+
'관측소',
|
|
469
|
+
'sea3003',
|
|
470
|
+
'용존산소',
|
|
471
|
+
'water',
|
|
472
|
+
'quality',
|
|
473
|
+
'ocean',
|
|
474
|
+
]) {
|
|
475
|
+
tokens.add(token)
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (isPpsBidQuery(query)) {
|
|
479
|
+
for (const token of [
|
|
480
|
+
'조달청',
|
|
481
|
+
'나라장터',
|
|
482
|
+
'입찰공고',
|
|
483
|
+
'공사입찰',
|
|
484
|
+
'bidntcenm',
|
|
485
|
+
'inqrybgndt',
|
|
486
|
+
'inqryenddt',
|
|
487
|
+
'pps',
|
|
488
|
+
'bid',
|
|
489
|
+
'procurement',
|
|
490
|
+
]) {
|
|
491
|
+
tokens.add(token)
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (isProtectedCheckQuery(query)) {
|
|
495
|
+
for (const token of [
|
|
496
|
+
'본인확인',
|
|
497
|
+
'인증',
|
|
498
|
+
'간편인증',
|
|
499
|
+
'모바일신분증',
|
|
500
|
+
'모바일id',
|
|
501
|
+
'소득금액증명원',
|
|
502
|
+
'증명원',
|
|
503
|
+
'홈택스',
|
|
504
|
+
'정부24',
|
|
505
|
+
'check',
|
|
506
|
+
'verify',
|
|
507
|
+
'identity',
|
|
508
|
+
'simple',
|
|
509
|
+
'auth',
|
|
510
|
+
'mobile',
|
|
511
|
+
'id',
|
|
512
|
+
'mydata',
|
|
513
|
+
]) {
|
|
514
|
+
tokens.add(token)
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (isTagoBusQuery(query)) {
|
|
518
|
+
for (const token of [
|
|
519
|
+
'국토교통부',
|
|
520
|
+
'tago',
|
|
521
|
+
'버스',
|
|
522
|
+
'시내버스',
|
|
523
|
+
'버스정류소',
|
|
524
|
+
'정류장',
|
|
525
|
+
'정류소',
|
|
526
|
+
'노선',
|
|
527
|
+
'노선번호',
|
|
528
|
+
'버스도착',
|
|
529
|
+
'도착',
|
|
530
|
+
'nodeid',
|
|
531
|
+
'nodenm',
|
|
532
|
+
'nodeno',
|
|
533
|
+
'routeid',
|
|
534
|
+
'routeno',
|
|
535
|
+
'citycode',
|
|
536
|
+
'bus',
|
|
537
|
+
'station',
|
|
538
|
+
'route',
|
|
539
|
+
'arrival',
|
|
540
|
+
]) {
|
|
541
|
+
tokens.add(token)
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (collapseOrAedQuery) {
|
|
292
545
|
for (const token of ['aed', '자동심장충격기', '자동제세동기', '심장충격기', '위치']) {
|
|
293
546
|
tokens.add(token)
|
|
294
547
|
}
|
|
@@ -328,6 +581,59 @@ function expandedQueryTokens(query: string): Set<string> {
|
|
|
328
581
|
tokens.add(token)
|
|
329
582
|
}
|
|
330
583
|
}
|
|
584
|
+
if (airportAviationQuery) {
|
|
585
|
+
for (const token of [
|
|
586
|
+
'metar',
|
|
587
|
+
'speci',
|
|
588
|
+
'amos',
|
|
589
|
+
'항공기상',
|
|
590
|
+
'공항기상',
|
|
591
|
+
'항공',
|
|
592
|
+
'비행기',
|
|
593
|
+
'항공편',
|
|
594
|
+
'운항',
|
|
595
|
+
'이륙',
|
|
596
|
+
'시정',
|
|
597
|
+
'rvr',
|
|
598
|
+
'wind',
|
|
599
|
+
'visibility',
|
|
600
|
+
]) {
|
|
601
|
+
tokens.add(token)
|
|
602
|
+
}
|
|
603
|
+
if (KMA_GIMPO_AIRPORT_RE.test(query) && KMA_RUNWAY_AREA_RE.test(query)) {
|
|
604
|
+
for (const token of [
|
|
605
|
+
'amos',
|
|
606
|
+
'공항기상관측',
|
|
607
|
+
'매분자료',
|
|
608
|
+
'활주로',
|
|
609
|
+
'김포공항',
|
|
610
|
+
'stn110',
|
|
611
|
+
'runway',
|
|
612
|
+
'visibility',
|
|
613
|
+
]) {
|
|
614
|
+
tokens.add(token)
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (KMA_ANALYSIS_DATA_RE.test(query)) {
|
|
619
|
+
for (const token of [
|
|
620
|
+
'분석자료',
|
|
621
|
+
'고해상도',
|
|
622
|
+
'격자자료',
|
|
623
|
+
'객관분석',
|
|
624
|
+
'aws',
|
|
625
|
+
'분석일기도',
|
|
626
|
+
'지도',
|
|
627
|
+
'비구름',
|
|
628
|
+
'바람흐름',
|
|
629
|
+
'objective',
|
|
630
|
+
'analysis',
|
|
631
|
+
'grid',
|
|
632
|
+
'chart',
|
|
633
|
+
]) {
|
|
634
|
+
tokens.add(token)
|
|
635
|
+
}
|
|
636
|
+
}
|
|
331
637
|
if (/(교통사고|사고\s*위험|사고다발|위험\s*(구간|도로|지점)|어린이보호구역|보호구역|도로\s*구간|accident|hazard|hotspot)/u.test(compact)) {
|
|
332
638
|
for (const token of [
|
|
333
639
|
'교통사고',
|
|
@@ -361,7 +667,10 @@ function expandedQueryTokens(query: string): Set<string> {
|
|
|
361
667
|
tokens.add(token)
|
|
362
668
|
}
|
|
363
669
|
}
|
|
364
|
-
if (
|
|
670
|
+
if (
|
|
671
|
+
!airportAviationQuery &&
|
|
672
|
+
/(근처|주변|인근|가까운|역|터미널|공항|캠퍼스|대학교|대학|해수욕장|시장|공원|랜드마크|nearby|around)/u.test(compact)
|
|
673
|
+
) {
|
|
365
674
|
for (const token of [
|
|
366
675
|
'장소',
|
|
367
676
|
'키워드',
|
|
@@ -395,6 +704,80 @@ function queryTargetsKoroadHazardDataset(query: string): boolean {
|
|
|
395
704
|
return /(사고\s*위험|위험\s*(구간|도로|지점)|도로\s*구간|어린이보호구역|보호구역|스쿨존|행정동코드|adm_cd|hazard|hotspot)/iu.test(query)
|
|
396
705
|
}
|
|
397
706
|
|
|
707
|
+
function isAirportAviationQuery(query: string): boolean {
|
|
708
|
+
return KMA_AIRPORT_NAME_RE.test(query) && KMA_AIRPORT_AVIATION_RE.test(query)
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function isMedicalEmergencyQuery(query: string): boolean {
|
|
712
|
+
return (
|
|
713
|
+
(EMERGENCY_REQUEST_RE.test(query) ||
|
|
714
|
+
AED_REQUEST_RE.test(query) ||
|
|
715
|
+
MEDICAL_COLLAPSE_RE.test(query)) &&
|
|
716
|
+
!MOIS_EMERGENCY_CALL_BOX_RE.test(query)
|
|
717
|
+
)
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function isCollapseOrAedQuery(query: string): boolean {
|
|
721
|
+
return (
|
|
722
|
+
(AED_REQUEST_RE.test(query) || MEDICAL_COLLAPSE_RE.test(query)) &&
|
|
723
|
+
!MOIS_EMERGENCY_CALL_BOX_RE.test(query)
|
|
724
|
+
)
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function isLocationAdapter(entry: AdapterManifestEntry): boolean {
|
|
728
|
+
return entry.primitive === 'locate' || ROOT_PRIMITIVE_TOOL_NAMES.has(entry.tool_id)
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function isKmaAnalysisQuery(query: string): boolean {
|
|
732
|
+
return KMA_ANALYSIS_DATA_RE.test(query)
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
function isLifestyleWeatherQuery(query: string): boolean {
|
|
736
|
+
return (
|
|
737
|
+
KMA_LIFESTYLE_WEATHER_RE.test(query) &&
|
|
738
|
+
!isAirportAviationQuery(query) &&
|
|
739
|
+
!isKmaAnalysisQuery(query) &&
|
|
740
|
+
!isMedicalEmergencyQuery(query) &&
|
|
741
|
+
!TRAFFIC_HAZARD_RE.test(query) &&
|
|
742
|
+
!MOF_OCEAN_WATER_QUALITY_RE.test(query)
|
|
743
|
+
)
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function isPpsBidQuery(query: string): boolean {
|
|
747
|
+
return PPS_BID_RE.test(query) && !PPS_SHOPPING_RE.test(query)
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function isProtectedCheckQuery(query: string): boolean {
|
|
751
|
+
return PROTECTED_QUERY_RE.test(query)
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function protectedCheckToolPreference(query: string): string[] {
|
|
755
|
+
const preferred = [
|
|
756
|
+
PROTECTED_MOBILE_ID_RE.test(query) ? 'mock_verify_mobile_id' : undefined,
|
|
757
|
+
PROTECTED_SIMPLE_AUTH_RE.test(query) ? 'mock_verify_module_simple_auth' : undefined,
|
|
758
|
+
PROTECTED_SIMPLE_AUTH_RE.test(query) ? 'mock_verify_ganpyeon_injeung' : undefined,
|
|
759
|
+
PROTECTED_MYDATA_RE.test(query) ? 'mock_verify_mydata' : undefined,
|
|
760
|
+
...PROTECTED_CHECK_TOOL_NAMES,
|
|
761
|
+
].filter((toolName): toolName is string => typeof toolName === 'string')
|
|
762
|
+
return [...new Set(preferred)]
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function isTagoBusQuery(query: string): boolean {
|
|
766
|
+
return TAGO_BUS_RE.test(query)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function isKmaAnalysisMapQuery(query: string): boolean {
|
|
770
|
+
return KMA_ANALYSIS_MAP_RE.test(query)
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
function isKmaAnalysisPointQuery(query: string): boolean {
|
|
774
|
+
return KMA_ANALYSIS_POINT_RE.test(query) && !isKmaAnalysisMapQuery(query)
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function queryPrefersPoiLocation(query: string): boolean {
|
|
778
|
+
return /(근처|주변|인근|가까운|역|터미널|공항|캠퍼스|대학교|대학|해수욕장|시장|공원|랜드마크|nearby|around)/iu.test(query)
|
|
779
|
+
}
|
|
780
|
+
|
|
398
781
|
function scoreAdapterEntry(
|
|
399
782
|
entry: AdapterManifestEntry,
|
|
400
783
|
queryTokens: Set<string>,
|
|
@@ -419,6 +802,7 @@ function scoreAdapterEntry(
|
|
|
419
802
|
if (description.includes(token)) score += 2
|
|
420
803
|
if (haystack.includes(token)) score += 1
|
|
421
804
|
}
|
|
805
|
+
if (query.toLowerCase().includes(entry.tool_id.toLowerCase())) score += 1000
|
|
422
806
|
if (
|
|
423
807
|
isReverseGeocodeAdapter(entry.tool_id) &&
|
|
424
808
|
!queryExplicitlyMentionsCoordinates(query)
|
|
@@ -429,9 +813,183 @@ function scoreAdapterEntry(
|
|
|
429
813
|
if (entry.tool_id === 'koroad_accident_hazard_search') score += 32
|
|
430
814
|
if (entry.tool_id === 'koroad_accident_search') score = 0
|
|
431
815
|
}
|
|
816
|
+
if (isKmaAnalysisQuery(query)) {
|
|
817
|
+
if (entry.tool_id === 'kma_apihub_url_analysis_weather_chart_image') {
|
|
818
|
+
score += isKmaAnalysisMapQuery(query) ? 900 : isKmaAnalysisPointQuery(query) ? -20 : 150
|
|
819
|
+
}
|
|
820
|
+
if (entry.tool_id === 'kma_apihub_url_high_resolution_grid_point') {
|
|
821
|
+
score += isKmaAnalysisPointQuery(query) ? 900 : 450
|
|
822
|
+
}
|
|
823
|
+
if (entry.tool_id === 'kma_apihub_url_aws_objective_analysis_grid') {
|
|
824
|
+
score += isKmaAnalysisPointQuery(query) ? 800 : 400
|
|
825
|
+
}
|
|
826
|
+
if (isKmaAnalysisPointQuery(query) && queryPrefersPoiLocation(query)) {
|
|
827
|
+
if (entry.tool_id === 'kakao_keyword_search') score += 30
|
|
828
|
+
if (entry.tool_id === 'kakao_address_search') score = Math.max(1, score - 15)
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
if (isLifestyleWeatherQuery(query)) {
|
|
832
|
+
if (entry.tool_id === 'kakao_keyword_search') score += 1100
|
|
833
|
+
if (entry.tool_id === 'kakao_address_search') score += 1000
|
|
834
|
+
if (entry.tool_id === 'kma_current_observation') score += 900
|
|
835
|
+
if (entry.tool_id === 'kma_ultra_short_term_forecast') score += 800
|
|
836
|
+
if (entry.tool_id === 'kma_short_term_forecast') score += 650
|
|
837
|
+
if (entry.tool_id === 'kakao_coord_to_region') score += 260
|
|
838
|
+
if (entry.tool_id === 'juso_adm_cd_lookup') score += 260
|
|
839
|
+
if (entry.tool_id === 'sgis_adm_cd_lookup') score += 260
|
|
840
|
+
}
|
|
841
|
+
if (HIRA_MEDICAL_DETAIL_RE.test(query)) {
|
|
842
|
+
if (entry.tool_id === 'hira_medical_institution_detail') score += 650
|
|
843
|
+
}
|
|
844
|
+
if (MOIS_EMERGENCY_CALL_BOX_RE.test(query)) {
|
|
845
|
+
if (entry.tool_id === 'mois_emergency_call_box_lookup') score += 1000
|
|
846
|
+
}
|
|
847
|
+
if (GYERYONG_ASSISTIVE_CHARGER_RE.test(query)) {
|
|
848
|
+
if (entry.tool_id === 'gyeryong_assistive_device_charging_place_locate') {
|
|
849
|
+
score += 1000
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
if (MOF_OCEAN_WATER_QUALITY_RE.test(query)) {
|
|
853
|
+
if (entry.tool_id === 'mof_ocean_water_quality_check') score += 1000
|
|
854
|
+
}
|
|
855
|
+
if (isPpsBidQuery(query)) {
|
|
856
|
+
if (entry.tool_id === 'pps_bid_public_info') score += 1000
|
|
857
|
+
}
|
|
858
|
+
if (isProtectedCheckQuery(query) && entry.primitive === 'check') {
|
|
859
|
+
const preference = protectedCheckToolPreference(query)
|
|
860
|
+
const index = preference.indexOf(entry.tool_id)
|
|
861
|
+
score += index >= 0 ? 1000 - index * 20 : 500
|
|
862
|
+
}
|
|
863
|
+
if (isTagoBusQuery(query)) {
|
|
864
|
+
if (entry.tool_id === 'tago_bus_station_search') score += 1050
|
|
865
|
+
if (entry.tool_id === 'tago_bus_arrival_search') score += 1000
|
|
866
|
+
if (entry.tool_id === 'tago_bus_route_station_search') score += 950
|
|
867
|
+
if (entry.tool_id === 'tago_bus_route_search') score += 850
|
|
868
|
+
if (entry.tool_id === 'tago_bus_location_search') score += 650
|
|
869
|
+
}
|
|
870
|
+
if (isCollapseOrAedQuery(query)) {
|
|
871
|
+
if (entry.tool_id === 'nmc_aed_site_locate') score += 900
|
|
872
|
+
if (entry.tool_id === 'nmc_emergency_search') score += 700
|
|
873
|
+
if (queryPrefersPoiLocation(query) && entry.tool_id === 'kakao_keyword_search') score += 120
|
|
874
|
+
}
|
|
875
|
+
if (
|
|
876
|
+
KMA_GIMPO_AIRPORT_RE.test(query) &&
|
|
877
|
+
KMA_RUNWAY_AREA_RE.test(query) &&
|
|
878
|
+
KMA_AIRPORT_AVIATION_RE.test(query) &&
|
|
879
|
+
entry.tool_id === 'kma_apihub_url_air_amos_minute'
|
|
880
|
+
) {
|
|
881
|
+
score += 500
|
|
882
|
+
}
|
|
432
883
|
return score
|
|
433
884
|
}
|
|
434
885
|
|
|
886
|
+
function filterSpecialCaseRanked(
|
|
887
|
+
query: string,
|
|
888
|
+
ranked: ScoredAdapterEntry[],
|
|
889
|
+
): ScoredAdapterEntry[] {
|
|
890
|
+
let filtered = ranked
|
|
891
|
+
if (isKmaAnalysisQuery(query)) {
|
|
892
|
+
const allowLocation = isKmaAnalysisPointQuery(query)
|
|
893
|
+
const preferPoiLocation = queryPrefersPoiLocation(query)
|
|
894
|
+
filtered = filtered
|
|
895
|
+
.filter(candidate => {
|
|
896
|
+
if (KMA_ANALYSIS_TOOL_NAMES.has(candidate.entry.tool_id)) return true
|
|
897
|
+
return allowLocation && isLocationAdapter(candidate.entry)
|
|
898
|
+
})
|
|
899
|
+
.map(candidate => {
|
|
900
|
+
if (!allowLocation || !isLocationAdapter(candidate.entry)) return candidate
|
|
901
|
+
let score = Math.max(1, candidate.score - 10)
|
|
902
|
+
if (preferPoiLocation && candidate.entry.tool_id === 'kakao_keyword_search') {
|
|
903
|
+
score += 30
|
|
904
|
+
} else if (preferPoiLocation && candidate.entry.tool_id === 'kakao_address_search') {
|
|
905
|
+
score = Math.max(1, score - 15)
|
|
906
|
+
}
|
|
907
|
+
return { ...candidate, score }
|
|
908
|
+
})
|
|
909
|
+
.sort((a, b) => {
|
|
910
|
+
if (b.score !== a.score) return b.score - a.score
|
|
911
|
+
return a.entry.tool_id.localeCompare(b.entry.tool_id)
|
|
912
|
+
})
|
|
913
|
+
}
|
|
914
|
+
if (isLifestyleWeatherQuery(query)) {
|
|
915
|
+
const allowed = filtered.filter(
|
|
916
|
+
candidate =>
|
|
917
|
+
KMA_LIFESTYLE_WEATHER_TOOL_NAMES.has(candidate.entry.tool_id) ||
|
|
918
|
+
isLocationAdapter(candidate.entry),
|
|
919
|
+
)
|
|
920
|
+
if (allowed.length > 0) {
|
|
921
|
+
filtered = allowed.sort((a, b) => {
|
|
922
|
+
if (b.score !== a.score) return b.score - a.score
|
|
923
|
+
return a.entry.tool_id.localeCompare(b.entry.tool_id)
|
|
924
|
+
})
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
if (isPpsBidQuery(query)) {
|
|
928
|
+
const allowed = filtered.filter(candidate => candidate.entry.tool_id === 'pps_bid_public_info')
|
|
929
|
+
if (allowed.length > 0) {
|
|
930
|
+
filtered = allowed.sort((a, b) => {
|
|
931
|
+
if (b.score !== a.score) return b.score - a.score
|
|
932
|
+
return a.entry.tool_id.localeCompare(b.entry.tool_id)
|
|
933
|
+
})
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
if (isProtectedCheckQuery(query)) {
|
|
937
|
+
const preference = protectedCheckToolPreference(query)
|
|
938
|
+
const allowed = filtered.filter(candidate => candidate.entry.primitive === 'check')
|
|
939
|
+
if (allowed.length > 0) {
|
|
940
|
+
filtered = allowed.sort((a, b) => {
|
|
941
|
+
const aIndex = preference.indexOf(a.entry.tool_id)
|
|
942
|
+
const bIndex = preference.indexOf(b.entry.tool_id)
|
|
943
|
+
const aRank = aIndex >= 0 ? aIndex : Number.MAX_SAFE_INTEGER
|
|
944
|
+
const bRank = bIndex >= 0 ? bIndex : Number.MAX_SAFE_INTEGER
|
|
945
|
+
if (aRank !== bRank) return aRank - bRank
|
|
946
|
+
if (b.score !== a.score) return b.score - a.score
|
|
947
|
+
return a.entry.tool_id.localeCompare(b.entry.tool_id)
|
|
948
|
+
})
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
if (isTagoBusQuery(query)) {
|
|
952
|
+
const allowed = filtered.filter(candidate => TAGO_BUS_TOOL_NAMES.has(candidate.entry.tool_id))
|
|
953
|
+
if (allowed.length > 0) {
|
|
954
|
+
filtered = allowed.sort((a, b) => {
|
|
955
|
+
if (b.score !== a.score) return b.score - a.score
|
|
956
|
+
return a.entry.tool_id.localeCompare(b.entry.tool_id)
|
|
957
|
+
})
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
if (isCollapseOrAedQuery(query)) {
|
|
961
|
+
const allowed = filtered.filter(candidate => {
|
|
962
|
+
if (candidate.entry.tool_id === 'nmc_aed_site_locate') return true
|
|
963
|
+
if (candidate.entry.tool_id === 'nmc_emergency_search') return true
|
|
964
|
+
return isLocationAdapter(candidate.entry)
|
|
965
|
+
})
|
|
966
|
+
if (allowed.some(candidate => candidate.entry.tool_id === 'nmc_aed_site_locate')) {
|
|
967
|
+
filtered = allowed.sort((a, b) => {
|
|
968
|
+
if (b.score !== a.score) return b.score - a.score
|
|
969
|
+
return a.entry.tool_id.localeCompare(b.entry.tool_id)
|
|
970
|
+
})
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
if (KMA_GIMHAE_AIRPORT_RE.test(query) && KMA_AIRPORT_AVIATION_RE.test(query)) {
|
|
974
|
+
filtered = filtered.filter(
|
|
975
|
+
candidate => candidate.entry.tool_id !== 'kma_apihub_url_air_amos_minute',
|
|
976
|
+
)
|
|
977
|
+
}
|
|
978
|
+
if (isAirportAviationQuery(query)) {
|
|
979
|
+
const hasAirUrlCandidate = filtered.some(candidate =>
|
|
980
|
+
KMA_URL_AIR_TOOL_NAMES.has(candidate.entry.tool_id),
|
|
981
|
+
)
|
|
982
|
+
if (hasAirUrlCandidate) {
|
|
983
|
+
filtered = filtered.filter(
|
|
984
|
+
candidate =>
|
|
985
|
+
!isLocationAdapter(candidate.entry) &&
|
|
986
|
+
candidate.entry.tool_id !== 'kma_current_observation',
|
|
987
|
+
)
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
return filtered
|
|
991
|
+
}
|
|
992
|
+
|
|
435
993
|
export function selectTopKAdapterToolNamesForQuery(
|
|
436
994
|
query: string,
|
|
437
995
|
maxResults = 5,
|
|
@@ -439,7 +997,9 @@ export function selectTopKAdapterToolNamesForQuery(
|
|
|
439
997
|
const normalizedQuery = query.trim()
|
|
440
998
|
if (!normalizedQuery || maxResults <= 0) return []
|
|
441
999
|
const queryTokens = expandedQueryTokens(normalizedQuery)
|
|
442
|
-
const ranked =
|
|
1000
|
+
const ranked = filterSpecialCaseRanked(
|
|
1001
|
+
normalizedQuery,
|
|
1002
|
+
listAdapters()
|
|
443
1003
|
.filter(entry => !ROOT_PRIMITIVE_TOOL_NAMES.has(entry.tool_id))
|
|
444
1004
|
.map(entry => ({
|
|
445
1005
|
entry,
|
|
@@ -449,7 +1009,8 @@ export function selectTopKAdapterToolNamesForQuery(
|
|
|
449
1009
|
.sort((a, b) => {
|
|
450
1010
|
if (b.score !== a.score) return b.score - a.score
|
|
451
1011
|
return a.entry.tool_id.localeCompare(b.entry.tool_id)
|
|
452
|
-
})
|
|
1012
|
+
}),
|
|
1013
|
+
)
|
|
453
1014
|
|
|
454
1015
|
return pickDiverseAdapterToolNames(ranked, maxResults)
|
|
455
1016
|
}
|
|
@@ -536,7 +1097,19 @@ function buildAdapterTool(entry: AdapterManifestEntry): Tool {
|
|
|
536
1097
|
].join('\n\n')
|
|
537
1098
|
},
|
|
538
1099
|
|
|
539
|
-
async validateInput(input) {
|
|
1100
|
+
async validateInput(input, context) {
|
|
1101
|
+
const directPublicDataChoice = validateDirectPublicDataToolChoice(
|
|
1102
|
+
entry.tool_id,
|
|
1103
|
+
context,
|
|
1104
|
+
input,
|
|
1105
|
+
)
|
|
1106
|
+
if (directPublicDataChoice) return directPublicDataChoice
|
|
1107
|
+
const kmaAviationChoice = validateKmaAviationToolChoice(entry.tool_id, context)
|
|
1108
|
+
if (kmaAviationChoice) return kmaAviationChoice
|
|
1109
|
+
const kmaAnalysisChoice = validateKmaAnalysisToolChoice(entry.tool_id, context)
|
|
1110
|
+
if (kmaAnalysisChoice) return kmaAnalysisChoice
|
|
1111
|
+
const nmcAedChoice = validateNmcAedToolChoice(entry.tool_id, context)
|
|
1112
|
+
if (nmcAedChoice) return nmcAedChoice
|
|
540
1113
|
if (!resolveAdapter(entry.tool_id)) {
|
|
541
1114
|
return {
|
|
542
1115
|
result: false as const,
|
|
@@ -551,14 +1124,24 @@ function buildAdapterTool(entry: AdapterManifestEntry): Tool {
|
|
|
551
1124
|
errorCode: 1,
|
|
552
1125
|
}
|
|
553
1126
|
}
|
|
1127
|
+
const contractInput = validateAdapterContractInput(
|
|
1128
|
+
entry.tool_id,
|
|
1129
|
+
input as Record<string, unknown>,
|
|
1130
|
+
)
|
|
1131
|
+
if (contractInput) return contractInput
|
|
554
1132
|
return { result: true as const }
|
|
555
1133
|
},
|
|
556
1134
|
|
|
557
1135
|
async call(input, context) {
|
|
1136
|
+
const normalizedInput = normalizeDirectPublicDataToolInput(
|
|
1137
|
+
entry.tool_id,
|
|
1138
|
+
context,
|
|
1139
|
+
input,
|
|
1140
|
+
)
|
|
558
1141
|
return dispatchPrimitive({
|
|
559
1142
|
primitive,
|
|
560
1143
|
toolName: entry.tool_id,
|
|
561
|
-
args:
|
|
1144
|
+
args: normalizedInput,
|
|
562
1145
|
context,
|
|
563
1146
|
registry: getOrCreatePendingCallRegistry(),
|
|
564
1147
|
bridge: getOrCreateUmmayaBridge(),
|