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
|
@@ -28,6 +28,11 @@ import {
|
|
|
28
28
|
} from '../../services/api/adapterManifest.js'
|
|
29
29
|
import { FIND_TOOL_NAME, DESCRIPTION, FIND_TOOL_PROMPT } from './prompt.js'
|
|
30
30
|
import { dispatchPrimitive } from '../_shared/dispatchPrimitive.js'
|
|
31
|
+
import { validateKmaAviationToolChoice } from '../_shared/kmaAviationGuard.js'
|
|
32
|
+
import { validateKmaAnalysisToolChoice } from '../_shared/kmaAnalysisGuard.js'
|
|
33
|
+
import { validateNmcAedToolChoice } from '../_shared/nmcAedGuard.js'
|
|
34
|
+
import { validateProtectedCheckToolChoice } from '../_shared/protectedCheckGuard.js'
|
|
35
|
+
import { validateDirectPublicDataToolChoice } from '../_shared/directPublicDataGuard.js'
|
|
31
36
|
import {
|
|
32
37
|
renderVerboseInputJson,
|
|
33
38
|
renderVerboseOutputJson,
|
|
@@ -38,6 +43,11 @@ import {
|
|
|
38
43
|
} from '../_shared/compactPrimitiveResult.js'
|
|
39
44
|
import { getOrCreateUmmayaBridge } from '../../ipc/bridgeSingleton.js'
|
|
40
45
|
import { getOrCreatePendingCallRegistry } from '../../ipc/pendingCallSingleton.js'
|
|
46
|
+
import {
|
|
47
|
+
isRootPrimitiveToolId,
|
|
48
|
+
normalizeRootPrimitiveAdapterEnvelope,
|
|
49
|
+
rootPrimitiveSelfTargetMessage,
|
|
50
|
+
} from '../_shared/rootPrimitiveInput.js'
|
|
41
51
|
|
|
42
52
|
// ---------------------------------------------------------------------------
|
|
43
53
|
// UMMAYA citation extension — attaches resolved citation to the context so the
|
|
@@ -48,8 +58,6 @@ type ContextWithCitation = ToolUseContext & {
|
|
|
48
58
|
ummayaCitations?: AdapterCitation[]
|
|
49
59
|
}
|
|
50
60
|
|
|
51
|
-
const ROOT_PRIMITIVE_TOOL_IDS = new Set(['find', 'locate', 'check', 'send'])
|
|
52
|
-
|
|
53
61
|
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
54
62
|
return value !== null && typeof value === 'object'
|
|
55
63
|
? value as Record<string, unknown>
|
|
@@ -531,19 +539,22 @@ function buildFindResultRows(output: Output): React.ReactNode[] {
|
|
|
531
539
|
// ---------------------------------------------------------------------------
|
|
532
540
|
|
|
533
541
|
const inputSchema = lazySchema(() =>
|
|
534
|
-
z.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
'
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
542
|
+
z.preprocess(
|
|
543
|
+
value => normalizeRootPrimitiveAdapterEnvelope(FIND_TOOL_NAME, value),
|
|
544
|
+
z.object({
|
|
545
|
+
tool_id: z
|
|
546
|
+
.string()
|
|
547
|
+
.min(1)
|
|
548
|
+
.describe(
|
|
549
|
+
'Concrete adapter identifier picked from <available_adapters>. ' +
|
|
550
|
+
'This is not the function name. Never use "find", "locate", "check", or "send". ' +
|
|
551
|
+
'Examples: "kma_forecast_fetch", "hira_hospital_search".',
|
|
552
|
+
),
|
|
553
|
+
params: z
|
|
554
|
+
.record(z.string(), z.unknown())
|
|
555
|
+
.describe('Adapter-defined Pydantic-validated parameter body'),
|
|
556
|
+
}),
|
|
557
|
+
),
|
|
547
558
|
)
|
|
548
559
|
type InputSchema = ReturnType<typeof inputSchema>
|
|
549
560
|
|
|
@@ -678,14 +689,29 @@ export const LookupPrimitive = buildTool({
|
|
|
678
689
|
// policy URL) is enforced at the primitive surface, not just at the
|
|
679
690
|
// permission gauntlet.
|
|
680
691
|
|
|
681
|
-
if (
|
|
692
|
+
if (isRootPrimitiveToolId(input.tool_id)) {
|
|
682
693
|
return {
|
|
683
694
|
result: false,
|
|
684
|
-
message:
|
|
695
|
+
message: rootPrimitiveSelfTargetMessage(input.tool_id, 'find'),
|
|
685
696
|
errorCode: PrimitiveErrorCode.AdapterNotFound,
|
|
686
697
|
}
|
|
687
698
|
}
|
|
688
699
|
|
|
700
|
+
const protectedChoice = validateProtectedCheckToolChoice(input.tool_id, context)
|
|
701
|
+
if (protectedChoice) return protectedChoice
|
|
702
|
+
const directPublicDataChoice = validateDirectPublicDataToolChoice(
|
|
703
|
+
input.tool_id,
|
|
704
|
+
context,
|
|
705
|
+
input.params,
|
|
706
|
+
)
|
|
707
|
+
if (directPublicDataChoice) return directPublicDataChoice
|
|
708
|
+
const kmaAviationChoice = validateKmaAviationToolChoice(input.tool_id, context)
|
|
709
|
+
if (kmaAviationChoice) return kmaAviationChoice
|
|
710
|
+
const kmaAnalysisChoice = validateKmaAnalysisToolChoice(input.tool_id, context)
|
|
711
|
+
if (kmaAnalysisChoice) return kmaAnalysisChoice
|
|
712
|
+
const nmcAedChoice = validateNmcAedToolChoice(input.tool_id, context)
|
|
713
|
+
if (nmcAedChoice) return nmcAedChoice
|
|
714
|
+
|
|
689
715
|
// Tier 1 — synced backend manifest (FR-017).
|
|
690
716
|
if (isManifestSynced()) {
|
|
691
717
|
const backendEntry = resolveAdapter(input.tool_id)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// UMMAYA-original — Epic #1634 P3 · FindPrimitive prompt strings.
|
|
3
3
|
// 2026 migration note: root primitives are lightweight category descriptors
|
|
4
|
-
// and legacy transcript compatibility wrappers. Concrete adapter
|
|
5
|
-
//
|
|
6
|
-
// retrieval, then
|
|
4
|
+
// and legacy transcript compatibility wrappers. Concrete adapter ids are
|
|
5
|
+
// selected through CC ToolSearch/deferred schema expansion or backend top-K
|
|
6
|
+
// retrieval, then exposed as concrete model-facing tool functions.
|
|
7
7
|
// Contract: specs/1634-tool-system-wiring/contracts/primitive-envelope.md § 2
|
|
8
8
|
|
|
9
9
|
export const FIND_TOOL_NAME = 'find'
|
|
10
10
|
|
|
11
11
|
/** Citizen-facing English description shown to the LLM (<= 240 chars). */
|
|
12
12
|
export const DESCRIPTION =
|
|
13
|
-
'Discover Korean public-service lookup adapters. Prefer concrete adapter functions loaded by ToolSearch or backend retrieval; find is a legacy wrapper
|
|
13
|
+
'Discover Korean public-service lookup adapters. Prefer concrete lookup adapter functions loaded by ToolSearch or backend retrieval; find is a legacy wrapper.'
|
|
14
14
|
|
|
15
15
|
/** Extended prompt included in the system-prompt tool-use section. */
|
|
16
16
|
export const FIND_TOOL_PROMPT = `Discover Korean public-service lookup adapters registered in the UMMAYA tool registry.
|
|
@@ -18,14 +18,15 @@ export const FIND_TOOL_PROMPT = `Discover Korean public-service lookup adapters
|
|
|
18
18
|
Preferred path:
|
|
19
19
|
- Call concrete adapter functions directly after their schemas are loaded.
|
|
20
20
|
- Example: kma_current_observation({ base_date: "YYYYMMDD", base_time: "HH00", nx: 97, ny: 74 })
|
|
21
|
-
- Adapter schemas are progressively disclosed by ToolSearch or
|
|
21
|
+
- Adapter ids and schemas are progressively disclosed by ToolSearch, adapter_manifest, or backend top-K retrieval for the current citizen request.
|
|
22
22
|
- Only top candidates should be loaded; do not expect every adapter schema in the prompt.
|
|
23
|
+
- A concrete adapter id may be valid even when it is not listed in <available-deferred-tools>; if it appears in <available_adapters> or adapter_manifest and its function is loaded, call that function directly with its schema fields.
|
|
23
24
|
|
|
24
25
|
Legacy root wrapper:
|
|
25
26
|
- If a concrete adapter function is not loaded and only the root primitive is available, find accepts { tool_id, params } for old transcripts and compatibility paths.
|
|
26
27
|
- tool_id must be a concrete adapter id from <available_adapters>, never "find", "locate", "check", or "send".
|
|
27
28
|
- Invalid: find({ tool_id: "find", params: {...} })
|
|
28
|
-
- Compatibility-only: find({ tool_id: "
|
|
29
|
+
- Compatibility-only: find({ tool_id: "kma_apihub_url_air_metar_decoded", params: { org: "K", help: 1 } })
|
|
29
30
|
|
|
30
31
|
Rules:
|
|
31
32
|
- Do not call find with mode='search' or query; discovery is handled outside the primitive call.
|
|
@@ -8,7 +8,7 @@ import React from 'react'
|
|
|
8
8
|
import { z } from 'zod/v4'
|
|
9
9
|
import { Text } from '../../ink.js'
|
|
10
10
|
import { MessageResponse } from '../../components/MessageResponse.js'
|
|
11
|
-
import { buildTool, type ToolDef } from '../../Tool.js'
|
|
11
|
+
import { buildTool, type ToolDef, type ToolUseContext } from '../../Tool.js'
|
|
12
12
|
import { lazySchema } from '../../utils/lazySchema.js'
|
|
13
13
|
import {
|
|
14
14
|
LOCATE_TOOL_NAME,
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
LOCATE_TOOL_PROMPT,
|
|
17
17
|
} from './prompt.js'
|
|
18
18
|
import { dispatchPrimitive } from '../_shared/dispatchPrimitive.js'
|
|
19
|
+
import { validateKmaAviationToolChoice } from '../_shared/kmaAviationGuard.js'
|
|
20
|
+
import { validateDirectPublicDataToolChoice } from '../_shared/directPublicDataGuard.js'
|
|
19
21
|
import {
|
|
20
22
|
renderVerboseInputJson,
|
|
21
23
|
renderVerboseOutputJson,
|
|
@@ -26,22 +28,29 @@ import {
|
|
|
26
28
|
} from '../_shared/compactPrimitiveResult.js'
|
|
27
29
|
import { getOrCreateUmmayaBridge } from '../../ipc/bridgeSingleton.js'
|
|
28
30
|
import { getOrCreatePendingCallRegistry } from '../../ipc/pendingCallSingleton.js'
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
import {
|
|
32
|
+
isRootPrimitiveToolId,
|
|
33
|
+
normalizeRootPrimitiveAdapterEnvelope,
|
|
34
|
+
rootPrimitiveSelfTargetMessage,
|
|
35
|
+
} from '../_shared/rootPrimitiveInput.js'
|
|
36
|
+
import { repairLocateQueryParamsFromConversation } from '../_shared/locationInputRepair.js'
|
|
31
37
|
|
|
32
38
|
const inputSchema = lazySchema(() =>
|
|
33
|
-
z.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
z.preprocess(
|
|
40
|
+
value => normalizeRootPrimitiveAdapterEnvelope(LOCATE_TOOL_NAME, value),
|
|
41
|
+
z.strictObject({
|
|
42
|
+
tool_id: z
|
|
43
|
+
.string()
|
|
44
|
+
.min(1)
|
|
45
|
+
.describe(
|
|
46
|
+
'Concrete locate adapter identifier from <available_adapters>. ' +
|
|
47
|
+
'This is not the function name. Never use "locate", "find", "check", or "send".',
|
|
48
|
+
),
|
|
49
|
+
params: z
|
|
50
|
+
.record(z.string(), z.unknown())
|
|
51
|
+
.describe('Adapter-defined Pydantic-validated parameter body.'),
|
|
52
|
+
}),
|
|
53
|
+
),
|
|
45
54
|
)
|
|
46
55
|
type InputSchema = ReturnType<typeof inputSchema>
|
|
47
56
|
|
|
@@ -260,14 +269,22 @@ export const ResolveLocationPrimitive = buildTool({
|
|
|
260
269
|
|
|
261
270
|
isMcp: false,
|
|
262
271
|
|
|
263
|
-
async validateInput(input: z.infer<InputSchema
|
|
264
|
-
if (
|
|
272
|
+
async validateInput(input: z.infer<InputSchema>, context: ToolUseContext) {
|
|
273
|
+
if (isRootPrimitiveToolId(input.tool_id)) {
|
|
265
274
|
return {
|
|
266
275
|
result: false as const,
|
|
267
|
-
message:
|
|
276
|
+
message: rootPrimitiveSelfTargetMessage(input.tool_id, 'locate'),
|
|
268
277
|
errorCode: 1,
|
|
269
278
|
}
|
|
270
279
|
}
|
|
280
|
+
const kmaAviationChoice = validateKmaAviationToolChoice(input.tool_id, context)
|
|
281
|
+
if (kmaAviationChoice) return kmaAviationChoice
|
|
282
|
+
const directPublicDataChoice = validateDirectPublicDataToolChoice(
|
|
283
|
+
input.tool_id,
|
|
284
|
+
context,
|
|
285
|
+
input.params,
|
|
286
|
+
)
|
|
287
|
+
if (directPublicDataChoice) return directPublicDataChoice
|
|
271
288
|
return { result: true as const }
|
|
272
289
|
},
|
|
273
290
|
|
|
@@ -307,9 +324,13 @@ export const ResolveLocationPrimitive = buildTool({
|
|
|
307
324
|
},
|
|
308
325
|
|
|
309
326
|
async call(input, context) {
|
|
327
|
+
const repairedInput = repairLocateQueryParamsFromConversation(
|
|
328
|
+
input as Record<string, unknown>,
|
|
329
|
+
context.messages,
|
|
330
|
+
)
|
|
310
331
|
return dispatchPrimitive<Output>({
|
|
311
332
|
primitive: 'locate',
|
|
312
|
-
args:
|
|
333
|
+
args: repairedInput,
|
|
313
334
|
context,
|
|
314
335
|
registry: getOrCreatePendingCallRegistry(),
|
|
315
336
|
bridge: getOrCreateUmmayaBridge(),
|
|
@@ -37,6 +37,11 @@ import {
|
|
|
37
37
|
} from '../_shared/compactPrimitiveResult.js'
|
|
38
38
|
import { getOrCreateUmmayaBridge } from '../../ipc/bridgeSingleton.js'
|
|
39
39
|
import { getOrCreatePendingCallRegistry } from '../../ipc/pendingCallSingleton.js'
|
|
40
|
+
import {
|
|
41
|
+
isRootPrimitiveToolId,
|
|
42
|
+
normalizeRootPrimitiveAdapterEnvelope,
|
|
43
|
+
rootPrimitiveSelfTargetMessage,
|
|
44
|
+
} from '../_shared/rootPrimitiveInput.js'
|
|
40
45
|
|
|
41
46
|
// ---------------------------------------------------------------------------
|
|
42
47
|
// UMMAYA citation extension — augments context at runtime for permission UI.
|
|
@@ -52,15 +57,18 @@ type ContextWithCitation = ToolUseContext & {
|
|
|
52
57
|
// ---------------------------------------------------------------------------
|
|
53
58
|
|
|
54
59
|
const inputSchema = lazySchema(() =>
|
|
55
|
-
z.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
z.preprocess(
|
|
61
|
+
value => normalizeRootPrimitiveAdapterEnvelope(SEND_TOOL_NAME, value),
|
|
62
|
+
z.strictObject({
|
|
63
|
+
tool_id: z
|
|
64
|
+
.string()
|
|
65
|
+
.min(1)
|
|
66
|
+
.describe('Registered send adapter identifier from <available_adapters>'),
|
|
67
|
+
params: z
|
|
68
|
+
.record(z.string(), z.unknown())
|
|
69
|
+
.describe('Adapter-defined Pydantic-validated parameter body'),
|
|
70
|
+
}),
|
|
71
|
+
),
|
|
64
72
|
)
|
|
65
73
|
type InputSchema = ReturnType<typeof inputSchema>
|
|
66
74
|
|
|
@@ -285,6 +293,14 @@ export const SubmitPrimitive = buildTool({
|
|
|
285
293
|
// 1002 contract (Spec 024 invariant: every adapter cites the agency
|
|
286
294
|
// policy URL) is enforced at the primitive surface.
|
|
287
295
|
|
|
296
|
+
if (isRootPrimitiveToolId(input.tool_id)) {
|
|
297
|
+
return {
|
|
298
|
+
result: false as const,
|
|
299
|
+
message: rootPrimitiveSelfTargetMessage(input.tool_id, 'send'),
|
|
300
|
+
errorCode: PrimitiveErrorCode.AdapterNotFound,
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
288
304
|
// Tier 1 — synced backend manifest (FR-017).
|
|
289
305
|
if (isManifestSynced()) {
|
|
290
306
|
const backendEntry = resolveAdapter(input.tool_id)
|
|
@@ -37,6 +37,11 @@ import {
|
|
|
37
37
|
} from '../_shared/compactPrimitiveResult.js'
|
|
38
38
|
import { getOrCreateUmmayaBridge } from '../../ipc/bridgeSingleton.js'
|
|
39
39
|
import { getOrCreatePendingCallRegistry } from '../../ipc/pendingCallSingleton.js'
|
|
40
|
+
import {
|
|
41
|
+
isRootPrimitiveToolId,
|
|
42
|
+
normalizeRootPrimitiveAdapterEnvelope,
|
|
43
|
+
rootPrimitiveSelfTargetMessage,
|
|
44
|
+
} from '../_shared/rootPrimitiveInput.js'
|
|
40
45
|
|
|
41
46
|
// ---------------------------------------------------------------------------
|
|
42
47
|
// UMMAYA citation extension — augments context at runtime for permission UI.
|
|
@@ -52,15 +57,18 @@ type ContextWithCitation = ToolUseContext & {
|
|
|
52
57
|
// ---------------------------------------------------------------------------
|
|
53
58
|
|
|
54
59
|
const inputSchema = lazySchema(() =>
|
|
55
|
-
z.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
z.preprocess(
|
|
61
|
+
value => normalizeRootPrimitiveAdapterEnvelope(CHECK_TOOL_NAME, value),
|
|
62
|
+
z.strictObject({
|
|
63
|
+
tool_id: z
|
|
64
|
+
.string()
|
|
65
|
+
.min(1)
|
|
66
|
+
.describe('Auth adapter identifier, e.g. "mock_verify_mobile_id"'),
|
|
67
|
+
params: z
|
|
68
|
+
.record(z.string(), z.unknown())
|
|
69
|
+
.describe('Adapter-defined credential parameter body'),
|
|
70
|
+
}),
|
|
71
|
+
),
|
|
64
72
|
)
|
|
65
73
|
type InputSchema = ReturnType<typeof inputSchema>
|
|
66
74
|
|
|
@@ -276,6 +284,14 @@ export const VerifyPrimitive = buildTool({
|
|
|
276
284
|
// Epic ε #2296 T013 — two-tier resolution (FR-017 / FR-018 / FR-019 / FR-020).
|
|
277
285
|
// Spec 2521 (2026-05-01) — citation-missing branch added (1002).
|
|
278
286
|
|
|
287
|
+
if (isRootPrimitiveToolId(input.tool_id)) {
|
|
288
|
+
return {
|
|
289
|
+
result: false as const,
|
|
290
|
+
message: rootPrimitiveSelfTargetMessage(input.tool_id, 'check'),
|
|
291
|
+
errorCode: PrimitiveErrorCode.AdapterNotFound,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
279
295
|
// Tier 1 — synced backend manifest (FR-017).
|
|
280
296
|
if (isManifestSynced()) {
|
|
281
297
|
const backendEntry = resolveAdapter(input.tool_id)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const SYNTHETIC_USER_CONTEXT_RE =
|
|
2
|
+
/<available_adapters\b|<\/available_adapters>|<available-deferred-tools\b|<\/available-deferred-tools>|##\s*Available tools|Current session context|Concrete UMMAYA|Pick a concrete adapter from <available_adapters>|Prefer concrete adapter function calls|<tool_use_error\b|<\/tool_use_error>|AdapterNotFound:|Permission delegation required:|tool-choice mismatch|Required follow-up for this tool chain|Emergency evidence chain complete|KMA analyzed weather-chart|Protected-domain/iu
|
|
3
|
+
|
|
4
|
+
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
5
|
+
return typeof value === 'object' && value !== null
|
|
6
|
+
? (value as Record<string, unknown>)
|
|
7
|
+
: undefined
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function messageContent(message: unknown): unknown {
|
|
11
|
+
const outer = asRecord(message)
|
|
12
|
+
const inner = asRecord(outer?.message)
|
|
13
|
+
return inner?.content ?? outer?.content
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function contentHasToolResult(content: unknown): boolean {
|
|
17
|
+
if (!Array.isArray(content)) return false
|
|
18
|
+
return content.some(block => asRecord(block)?.type === 'tool_result')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isSyntheticUserMessage(message: unknown): boolean {
|
|
22
|
+
const outer = asRecord(message)
|
|
23
|
+
const inner = asRecord(outer?.message)
|
|
24
|
+
return (
|
|
25
|
+
outer?.isMeta === true ||
|
|
26
|
+
inner?.isMeta === true ||
|
|
27
|
+
outer?.isCompactSummary === true ||
|
|
28
|
+
outer?.isVisibleInTranscriptOnly === true ||
|
|
29
|
+
outer?.toolUseResult !== undefined ||
|
|
30
|
+
outer?.sourceToolAssistantUUID !== undefined ||
|
|
31
|
+
contentHasToolResult(messageContent(message))
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isSyntheticUserText(text: string): boolean {
|
|
36
|
+
const trimmed = text.trim()
|
|
37
|
+
return trimmed.length > 0 && SYNTHETIC_USER_CONTEXT_RE.test(trimmed)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isNonSyntheticUserText(text: string): boolean {
|
|
41
|
+
return text.trim().length > 0 && !isSyntheticUserText(text)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isNonSyntheticUserMessageText(
|
|
45
|
+
message: unknown,
|
|
46
|
+
text: string,
|
|
47
|
+
): boolean {
|
|
48
|
+
return !isSyntheticUserMessage(message) && isNonSyntheticUserText(text)
|
|
49
|
+
}
|