ARCH: удерживать mixed metadata ambiguity как явное clarification state
This commit is contained in:
parent
c0b3296953
commit
40cf71d118
|
|
@ -109,6 +109,13 @@ function isMetadataPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): bo
|
||||||
return pilot.pilot_scope === "metadata_inspection_v1";
|
return pilot.pilot_scope === "metadata_inspection_v1";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isMetadataLaneChoiceClarification(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean {
|
||||||
|
return (
|
||||||
|
pilot.reason_codes.includes("planner_selected_metadata_lane_clarification_recipe") ||
|
||||||
|
pilot.dry_run.reason_codes.includes("planner_selected_metadata_lane_clarification_recipe")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function metadataRouteFamilyLabelRu(
|
function metadataRouteFamilyLabelRu(
|
||||||
routeFamily: "document_evidence" | "movement_evidence" | "catalog_drilldown" | null
|
routeFamily: "document_evidence" | "movement_evidence" | "catalog_drilldown" | null
|
||||||
): string | null {
|
): string | null {
|
||||||
|
|
@ -167,6 +174,12 @@ function headlineFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD
|
||||||
if (mode === "bounded_inference_only") {
|
if (mode === "bounded_inference_only") {
|
||||||
return "Точный факт не подтвержден, но есть ограниченная оценка по найденной активности в 1С.";
|
return "Точный факт не подтвержден, но есть ограниченная оценка по найденной активности в 1С.";
|
||||||
}
|
}
|
||||||
|
if (mode === "needs_clarification" && isMetadataLaneChoiceClarification(pilot)) {
|
||||||
|
return "По подтвержденной metadata-поверхности видно несколько конкурирующих data-lane, и без явного выбора дальше идти нельзя.";
|
||||||
|
}
|
||||||
|
if (mode === "needs_clarification" && isMetadataLaneChoiceClarification(pilot)) {
|
||||||
|
return "Уточните, в какой контур идти дальше: по документам или по движениям/регистрам.";
|
||||||
|
}
|
||||||
if (mode === "needs_clarification") {
|
if (mode === "needs_clarification") {
|
||||||
return "Нужно уточнить контекст перед поиском в 1С.";
|
return "Нужно уточнить контекст перед поиском в 1С.";
|
||||||
}
|
}
|
||||||
|
|
@ -177,6 +190,9 @@ function headlineFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextStepFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpDiscoveryPilotExecutionContract): string | null {
|
function nextStepFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpDiscoveryPilotExecutionContract): string | null {
|
||||||
|
if (mode === "needs_clarification" && isMetadataLaneChoiceClarification(pilot)) {
|
||||||
|
return "Уточните, в какой контур идти дальше: по документам или по движениям/регистрам.";
|
||||||
|
}
|
||||||
if (mode === "needs_clarification") {
|
if (mode === "needs_clarification") {
|
||||||
return "Уточните контрагента, период или организацию, и я смогу выполнить проверку по 1С.";
|
return "Уточните контрагента, период или организацию, и я смогу выполнить проверку по 1С.";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,16 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||||
const requestedAggregationAxis = aggregationAxis(meaning);
|
const requestedAggregationAxis = aggregationAxis(meaning);
|
||||||
addScopeAxes(axes, meaning);
|
addScopeAxes(axes, meaning);
|
||||||
|
|
||||||
|
if (includesAny(combined, ["metadata_lane_choice_clarification", "resolve_next_lane"])) {
|
||||||
|
pushUnique(axes, "lane_family_choice");
|
||||||
|
return {
|
||||||
|
semanticDataNeed: "metadata lane clarification",
|
||||||
|
primitives: [],
|
||||||
|
axes,
|
||||||
|
reason: "planner_selected_metadata_lane_clarification_recipe"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (includesAny(combined, ["turnover", "revenue", "payment", "payout", "value", "net", "netting", "balance", "cashflow"])) {
|
if (includesAny(combined, ["turnover", "revenue", "payment", "payout", "value", "net", "netting", "balance", "cashflow"])) {
|
||||||
pushUnique(axes, "aggregate_axis");
|
pushUnique(axes, "aggregate_axis");
|
||||||
pushUnique(axes, "amount");
|
pushUnique(axes, "amount");
|
||||||
|
|
|
||||||
|
|
@ -601,6 +601,19 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
!metadataMovementHintSignal &&
|
!metadataMovementHintSignal &&
|
||||||
hasMetadataDownstreamContinuationSignal(rawText)
|
hasMetadataDownstreamContinuationSignal(rawText)
|
||||||
);
|
);
|
||||||
|
const metadataAmbiguityLaneClarificationApplicable = Boolean(
|
||||||
|
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
|
!metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
|
!metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
|
followupSeed.counterparty &&
|
||||||
|
!rawLifecycleSignal &&
|
||||||
|
!rawValueFlowSignal &&
|
||||||
|
!rawMetadataSignal &&
|
||||||
|
!metadataDocumentHintSignal &&
|
||||||
|
!metadataMovementHintSignal &&
|
||||||
|
hasMetadataDownstreamContinuationSignal(rawText)
|
||||||
|
);
|
||||||
const metadataGroundedDocumentLaneApplicable =
|
const metadataGroundedDocumentLaneApplicable =
|
||||||
metadataGroundedDocumentFollowupApplicable ||
|
metadataGroundedDocumentFollowupApplicable ||
|
||||||
metadataAmbiguityResolvedDocumentFollowupApplicable ||
|
metadataAmbiguityResolvedDocumentFollowupApplicable ||
|
||||||
|
|
@ -613,23 +626,30 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
metadataAmbiguityCollapsedMovementLaneContinuationApplicable;
|
metadataAmbiguityCollapsedMovementLaneContinuationApplicable;
|
||||||
const effectiveMetadataFollowupSeedApplicable =
|
const effectiveMetadataFollowupSeedApplicable =
|
||||||
metadataFollowupSeedApplicable &&
|
metadataFollowupSeedApplicable &&
|
||||||
|
!metadataAmbiguityLaneClarificationApplicable &&
|
||||||
!metadataGroundedDocumentLaneApplicable &&
|
!metadataGroundedDocumentLaneApplicable &&
|
||||||
!metadataGroundedMovementLaneApplicable;
|
!metadataGroundedMovementLaneApplicable;
|
||||||
const seededDomain = metadataGroundedDocumentLaneApplicable
|
const seededDomain = metadataAmbiguityLaneClarificationApplicable
|
||||||
|
? "metadata"
|
||||||
|
: metadataGroundedDocumentLaneApplicable
|
||||||
? "documents"
|
? "documents"
|
||||||
: metadataGroundedMovementLaneApplicable
|
: metadataGroundedMovementLaneApplicable
|
||||||
? "movements"
|
? "movements"
|
||||||
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
? followupSeed.domain
|
? followupSeed.domain
|
||||||
: null;
|
: null;
|
||||||
const seededAction = metadataGroundedDocumentLaneApplicable
|
const seededAction = metadataAmbiguityLaneClarificationApplicable
|
||||||
|
? "resolve_next_lane"
|
||||||
|
: metadataGroundedDocumentLaneApplicable
|
||||||
? "list_documents"
|
? "list_documents"
|
||||||
: metadataGroundedMovementLaneApplicable
|
: metadataGroundedMovementLaneApplicable
|
||||||
? "list_movements"
|
? "list_movements"
|
||||||
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
? followupSeed.action
|
? followupSeed.action
|
||||||
: null;
|
: null;
|
||||||
const seededUnsupported = metadataGroundedDocumentLaneApplicable
|
const seededUnsupported = metadataAmbiguityLaneClarificationApplicable
|
||||||
|
? "metadata_lane_choice_clarification"
|
||||||
|
: metadataGroundedDocumentLaneApplicable
|
||||||
? "document_evidence"
|
? "document_evidence"
|
||||||
: metadataGroundedMovementLaneApplicable
|
: metadataGroundedMovementLaneApplicable
|
||||||
? "movement_evidence"
|
? "movement_evidence"
|
||||||
|
|
@ -649,14 +669,16 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
valueFlowSignal &&
|
valueFlowSignal &&
|
||||||
!bidirectionalValueFlowSignal &&
|
!bidirectionalValueFlowSignal &&
|
||||||
(rawPayoutSignal || seededAction === "payout");
|
(rawPayoutSignal || seededAction === "payout");
|
||||||
const semanticDataNeed = semanticNeedFor({
|
const semanticDataNeed = metadataAmbiguityLaneClarificationApplicable
|
||||||
domain: rawDomain ?? seededDomain,
|
? "metadata lane clarification"
|
||||||
action: rawAction ?? seededAction,
|
: semanticNeedFor({
|
||||||
unsupported: unsupported ?? seededUnsupported,
|
domain: rawDomain ?? seededDomain,
|
||||||
lifecycleSignal,
|
action: rawAction ?? seededAction,
|
||||||
valueFlowSignal,
|
unsupported: unsupported ?? seededUnsupported,
|
||||||
metadataSignal: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
lifecycleSignal,
|
||||||
});
|
valueFlowSignal,
|
||||||
|
metadataSignal: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
|
});
|
||||||
const entityCandidates = collectEntityCandidates(assistantTurnMeaning?.explicit_entity_candidates);
|
const entityCandidates = collectEntityCandidates(assistantTurnMeaning?.explicit_entity_candidates);
|
||||||
pushUnique(entityCandidates, predecomposeEntities.counterparty);
|
pushUnique(entityCandidates, predecomposeEntities.counterparty);
|
||||||
pushUnique(entityCandidates, followupSeed.counterparty);
|
pushUnique(entityCandidates, followupSeed.counterparty);
|
||||||
|
|
@ -719,6 +741,8 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
? "movement_evidence"
|
? "movement_evidence"
|
||||||
: metadataGroundedDocumentLaneApplicable
|
: metadataGroundedDocumentLaneApplicable
|
||||||
? "document_evidence"
|
? "document_evidence"
|
||||||
|
: metadataAmbiguityLaneClarificationApplicable
|
||||||
|
? "metadata_lane_choice_clarification"
|
||||||
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? "1c_metadata_surface"
|
? "1c_metadata_surface"
|
||||||
: followupDiscoverySeedApplicable
|
: followupDiscoverySeedApplicable
|
||||||
|
|
@ -731,6 +755,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
valueFlowSignal ||
|
valueFlowSignal ||
|
||||||
metadataGroundedMovementLaneApplicable ||
|
metadataGroundedMovementLaneApplicable ||
|
||||||
metadataGroundedDocumentLaneApplicable ||
|
metadataGroundedDocumentLaneApplicable ||
|
||||||
|
metadataAmbiguityLaneClarificationApplicable ||
|
||||||
rawMetadataSignal ||
|
rawMetadataSignal ||
|
||||||
effectiveMetadataFollowupSeedApplicable ||
|
effectiveMetadataFollowupSeedApplicable ||
|
||||||
followupDiscoverySeedApplicable
|
followupDiscoverySeedApplicable
|
||||||
|
|
@ -773,13 +798,14 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
followupDiscoverySeedApplicable:
|
followupDiscoverySeedApplicable:
|
||||||
followupDiscoverySeedApplicable ||
|
followupDiscoverySeedApplicable ||
|
||||||
effectiveMetadataFollowupSeedApplicable ||
|
effectiveMetadataFollowupSeedApplicable ||
|
||||||
|
metadataAmbiguityLaneClarificationApplicable ||
|
||||||
metadataGroundedMovementLaneApplicable ||
|
metadataGroundedMovementLaneApplicable ||
|
||||||
metadataGroundedDocumentLaneApplicable
|
metadataGroundedDocumentLaneApplicable
|
||||||
});
|
});
|
||||||
const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0;
|
const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0;
|
||||||
const sourceSignal: AssistantMcpDiscoveryTurnInputSource = assistantTurnMeaning
|
const sourceSignal: AssistantMcpDiscoveryTurnInputSource = assistantTurnMeaning
|
||||||
? "assistant_turn_meaning"
|
? "assistant_turn_meaning"
|
||||||
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable || metadataAmbiguityLaneClarificationApplicable
|
||||||
? "followup_context"
|
? "followup_context"
|
||||||
: metadataGroundedMovementLaneApplicable
|
: metadataGroundedMovementLaneApplicable
|
||||||
? "followup_context"
|
? "followup_context"
|
||||||
|
|
@ -840,6 +866,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
if (metadataAmbiguityCollapsedMovementLaneContinuationApplicable) {
|
if (metadataAmbiguityCollapsedMovementLaneContinuationApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_collapsed_to_movement_lane");
|
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_collapsed_to_movement_lane");
|
||||||
}
|
}
|
||||||
|
if (metadataAmbiguityLaneClarificationApplicable) {
|
||||||
|
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_requires_lane_choice");
|
||||||
|
}
|
||||||
if (unsupported) {
|
if (unsupported) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,27 @@ describe("assistant MCP discovery answer adapter", () => {
|
||||||
expect(draft.must_not_claim).toContain("Do not claim rows were checked when mcp_execution_performed=false.");
|
expect(draft.must_not_claim).toContain("Do not claim rows were checked when mcp_execution_performed=false.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("asks for an explicit lane choice when mixed metadata ambiguity cannot continue on a neutral follow-up", async () => {
|
||||||
|
const planner = planAssistantMcpDiscovery({
|
||||||
|
turnMeaning: {
|
||||||
|
asked_domain_family: "metadata",
|
||||||
|
asked_action_family: "resolve_next_lane",
|
||||||
|
explicit_entity_candidates: ["SVK"],
|
||||||
|
explicit_date_scope: "2020",
|
||||||
|
unsupported_but_understood_family: "metadata_lane_choice_clarification"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const pilot = await executeAssistantMcpDiscoveryPilot(planner, buildDeps([]));
|
||||||
|
|
||||||
|
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
|
||||||
|
|
||||||
|
expect(draft.answer_mode).toBe("needs_clarification");
|
||||||
|
expect(draft.headline).toContain("data-lane");
|
||||||
|
expect(draft.next_step_line).toContain("по документам");
|
||||||
|
expect(draft.next_step_line).toContain("по движениям/регистрам");
|
||||||
|
expect(draft.must_not_claim).toContain("Do not claim rows were checked when mcp_execution_performed=false.");
|
||||||
|
});
|
||||||
|
|
||||||
it("turns metadata surface evidence into a human-safe metadata answer draft", async () => {
|
it("turns metadata surface evidence into a human-safe metadata answer draft", async () => {
|
||||||
const planner = planAssistantMcpDiscovery({
|
const planner = planAssistantMcpDiscovery({
|
||||||
turnMeaning: {
|
turnMeaning: {
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,26 @@ describe("assistant MCP discovery planner", () => {
|
||||||
expect(result.proposed_primitives).not.toContain("query_documents");
|
expect(result.proposed_primitives).not.toContain("query_documents");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps metadata lane-choice clarification in needs_clarification without launching MCP primitives", () => {
|
||||||
|
const result = planAssistantMcpDiscovery({
|
||||||
|
turnMeaning: {
|
||||||
|
asked_domain_family: "metadata",
|
||||||
|
asked_action_family: "resolve_next_lane",
|
||||||
|
explicit_entity_candidates: ["SVK"],
|
||||||
|
explicit_date_scope: "2020",
|
||||||
|
unsupported_but_understood_family: "metadata_lane_choice_clarification"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.planner_status).toBe("needs_clarification");
|
||||||
|
expect(result.semantic_data_need).toBe("metadata lane clarification");
|
||||||
|
expect(result.proposed_primitives).toEqual([]);
|
||||||
|
expect(result.required_axes).toEqual(["counterparty", "period", "lane_family_choice"]);
|
||||||
|
expect(result.discovery_plan.plan_status).toBe("needs_clarification");
|
||||||
|
expect(result.reason_codes).toContain("planner_selected_metadata_lane_clarification_recipe");
|
||||||
|
expect(result.reason_codes).toContain("planner_needs_more_user_or_scope_context");
|
||||||
|
});
|
||||||
|
|
||||||
it("does not mark an unclassified turn as executable without turn meaning context", () => {
|
it("does not mark an unclassified turn as executable without turn meaning context", () => {
|
||||||
const result = planAssistantMcpDiscovery({});
|
const result = planAssistantMcpDiscovery({});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -351,6 +351,34 @@ describe("assistant MCP discovery response candidate", () => {
|
||||||
expect(candidate.eligible_for_future_hot_runtime).toBe(true);
|
expect(candidate.eligible_for_future_hot_runtime).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("surfaces metadata lane-choice clarification as a user-facing clarification candidate", () => {
|
||||||
|
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||||
|
entryPoint({
|
||||||
|
bridge: {
|
||||||
|
bridge_status: "needs_clarification",
|
||||||
|
user_facing_response_allowed: true,
|
||||||
|
business_fact_answer_allowed: false,
|
||||||
|
requires_user_clarification: true,
|
||||||
|
answer_draft: {
|
||||||
|
answer_mode: "needs_clarification",
|
||||||
|
headline: "По подтвержденной metadata-поверхности видно несколько конкурирующих data-lane, и без явного выбора дальше идти нельзя.",
|
||||||
|
confirmed_lines: [],
|
||||||
|
inference_lines: [],
|
||||||
|
unknown_lines: [],
|
||||||
|
limitation_lines: [],
|
||||||
|
next_step_line: "Уточните, в какой контур идти дальше: по документам или по движениям/регистрам."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(candidate.candidate_status).toBe("clarification_candidate");
|
||||||
|
expect(candidate.reply_type).toBe("clarification_required");
|
||||||
|
expect(candidate.reply_text).toContain("data-lane");
|
||||||
|
expect(candidate.reply_text).toContain("по документам");
|
||||||
|
expect(candidate.reply_text).toContain("по движениям/регистрам");
|
||||||
|
});
|
||||||
|
|
||||||
it("does not expose unsupported bridge output as a future hot candidate", () => {
|
it("does not expose unsupported bridge output as a future hot candidate", () => {
|
||||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||||
entryPoint({
|
entryPoint({
|
||||||
|
|
|
||||||
|
|
@ -570,6 +570,38 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||||
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_collapsed_to_movement_lane");
|
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_collapsed_to_movement_lane");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("requires an explicit lane choice on a generic downstream follow-up when metadata ambiguity stays mixed", () => {
|
||||||
|
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||||
|
userMessage: "давай дальше",
|
||||||
|
followupContext: {
|
||||||
|
previous_discovery_pilot_scope: "metadata_inspection_v1",
|
||||||
|
previous_discovery_metadata_ambiguity_detected: true,
|
||||||
|
previous_discovery_metadata_ambiguity_entity_sets: ["Документ", "РегистрНакопления"],
|
||||||
|
previous_filters: {
|
||||||
|
counterparty: "SVK",
|
||||||
|
period_from: "2020-01-01",
|
||||||
|
period_to: "2020-12-31"
|
||||||
|
},
|
||||||
|
previous_anchor_type: "counterparty",
|
||||||
|
previous_anchor_value: "SVK"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.adapter_status).toBe("ready");
|
||||||
|
expect(result.should_run_discovery).toBe(true);
|
||||||
|
expect(result.source_signal).toBe("followup_context");
|
||||||
|
expect(result.semantic_data_need).toBe("metadata lane clarification");
|
||||||
|
expect(result.turn_meaning_ref).toMatchObject({
|
||||||
|
asked_domain_family: "metadata",
|
||||||
|
asked_action_family: "resolve_next_lane",
|
||||||
|
explicit_entity_candidates: ["SVK"],
|
||||||
|
explicit_date_scope: "2020",
|
||||||
|
unsupported_but_understood_family: "metadata_lane_choice_clarification",
|
||||||
|
stale_replay_forbidden: true
|
||||||
|
});
|
||||||
|
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_requires_lane_choice");
|
||||||
|
});
|
||||||
|
|
||||||
it("switches the checked year on a short payout follow-up while keeping prior discovery counterparty", () => {
|
it("switches the checked year on a short payout follow-up while keeping prior discovery counterparty", () => {
|
||||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||||
userMessage: "а теперь за 2021?",
|
userMessage: "а теперь за 2021?",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue