remove classify as a user facing tool
This commit is contained in:
+4
-4
@@ -1,7 +1,5 @@
|
||||
package stirling.software.proprietary.controller.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -19,6 +17,8 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import io.github.pixee.security.Filenames;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -152,8 +152,8 @@ public class ClassifyTagController {
|
||||
|
||||
/**
|
||||
* Override point for a future per-org / DB-configured taxonomy: resolve the caller's taxonomy
|
||||
* here and return it (engine shape) to classify against; {@code null} falls back to the engine's
|
||||
* generated default. Always null today.
|
||||
* here and return it (engine shape) to classify against; {@code null} falls back to the
|
||||
* engine's generated default. Always null today.
|
||||
*/
|
||||
private JsonNode resolveTaxonomyOverride() {
|
||||
return null;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"_generated": "AUTO-GENERATED from frontend/editor/src/proprietary/data/classificationTaxonomy.ts by editor/scripts/generate-taxonomy.mts — do NOT edit by hand; run `task frontend:taxonomy`.",
|
||||
"categories": [
|
||||
{
|
||||
"id": "invoice",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
@@ -36,7 +37,12 @@ WINDOW_PAGES = 2
|
||||
# `task frontend:taxonomy` — edit that file, not this JSON. Validated into the
|
||||
# typed contract on import, so a malformed entry fails fast.
|
||||
_DEFAULT_TAXONOMY_PATH = Path(__file__).with_name("default_taxonomy.generated.json")
|
||||
DEFAULT_TAXONOMY = ClassificationTaxonomy.model_validate_json(_DEFAULT_TAXONOMY_PATH.read_text(encoding="utf-8"))
|
||||
# The file carries an underscore-prefixed "_generated" notice (JSON has no
|
||||
# comments); drop meta keys before validating against the strict contract.
|
||||
_raw_taxonomy = json.loads(_DEFAULT_TAXONOMY_PATH.read_text(encoding="utf-8"))
|
||||
DEFAULT_TAXONOMY = ClassificationTaxonomy.model_validate(
|
||||
{key: value for key, value in _raw_taxonomy.items() if not key.startswith("_")}
|
||||
)
|
||||
|
||||
|
||||
_SYSTEM_PROMPT = (
|
||||
|
||||
@@ -63,7 +63,6 @@ class WorkflowOutcome(StrEnum):
|
||||
UNSUPPORTED_CAPABILITY = "unsupported_capability"
|
||||
GENERATE_FILE = "generate_file"
|
||||
CONVERT_MARKDOWN = "convert_markdown"
|
||||
CLASSIFICATION = "classification"
|
||||
|
||||
|
||||
class ArtifactKind(StrEnum):
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from stirling.models import ApiModel
|
||||
|
||||
from .common import WorkflowOutcome
|
||||
from .documents import PageText
|
||||
|
||||
|
||||
@@ -55,10 +52,11 @@ class DocumentClassificationResponse(ApiModel):
|
||||
|
||||
``category`` and ``doc_type`` are ids drawn from the taxonomy, or the
|
||||
sentinel ``"unknown"`` when the model's answer fell outside it. ``tags`` are
|
||||
the subset of the model's tags that exist in the taxonomy.
|
||||
the subset of the model's tags that exist in the taxonomy. This is a plain
|
||||
answer from a dedicated endpoint — it carries no ``outcome`` discriminator
|
||||
(it isn't one of the orchestrator's WorkflowOutcome-routed union responses).
|
||||
"""
|
||||
|
||||
outcome: Literal[WorkflowOutcome.CLASSIFICATION] = WorkflowOutcome.CLASSIFICATION
|
||||
category: str
|
||||
doc_type: str
|
||||
type_confidence: float = Field(ge=0.0, le=1.0)
|
||||
|
||||
@@ -44,7 +44,6 @@ def test_classify_returns_camel_cased_result(classification_client: TestClient)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["outcome"] == "classification"
|
||||
assert body["category"] == "contract"
|
||||
assert body["docType"] == "nda"
|
||||
assert body["typeConfidence"] == 0.96
|
||||
|
||||
@@ -4298,10 +4298,6 @@ desc = "Compares and shows the differences between 2 PDF Documents"
|
||||
tags = "difference,compare,diff,compare PDFs,compare documents,find differences,show differences,changes,what changed,track changes,revisions,version compare,side by side,contrast,delta"
|
||||
title = "Compare"
|
||||
|
||||
[home.classify]
|
||||
desc = "Identify a document's type and tag its metadata."
|
||||
title = "Classify"
|
||||
|
||||
[home.compress]
|
||||
desc = "Compress PDFs to reduce their file size."
|
||||
tags = "shrink,reduce,optimize,compress,smaller,downsize,file size,reduce size,minimize,make smaller,decrease size,optimize size"
|
||||
|
||||
@@ -34,7 +34,15 @@ const outPath = resolve(
|
||||
"engine/src/stirling/agents/default_taxonomy.generated.json",
|
||||
);
|
||||
|
||||
const json = JSON.stringify(DEFAULT_CLASSIFICATION_TAXONOMY, null, 2) + "\n";
|
||||
const NOTICE =
|
||||
"AUTO-GENERATED from frontend/editor/src/proprietary/data/classificationTaxonomy.ts " +
|
||||
"by editor/scripts/generate-taxonomy.mts — do NOT edit by hand; run `task frontend:taxonomy`.";
|
||||
const json =
|
||||
JSON.stringify(
|
||||
{ _generated: NOTICE, ...DEFAULT_CLASSIFICATION_TAXONOMY },
|
||||
null,
|
||||
2,
|
||||
) + "\n";
|
||||
|
||||
if (process.argv.includes("--check")) {
|
||||
const current = existsSync(outPath) ? readFileSync(outPath, "utf8") : "";
|
||||
|
||||
@@ -489,6 +489,7 @@ export async function runPolicyOnFile(
|
||||
backendId: string,
|
||||
fileId: FileId,
|
||||
fileName: string,
|
||||
replaceRunId?: string,
|
||||
): Promise<void> {
|
||||
// A freshly-uploaded file's bytes are written to IndexedDB asynchronously, so
|
||||
// its stub can appear in the file list a beat before getStirlingFile resolves
|
||||
@@ -516,6 +517,7 @@ export async function runPolicyOnFile(
|
||||
}
|
||||
try {
|
||||
const runId = await runStoredPolicy(backendId, [file]);
|
||||
if (replaceRunId) removeRun(replaceRunId);
|
||||
// recordRunStart marks this (policy, file) dispatched as it records the run.
|
||||
recordRunStart({
|
||||
runId,
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { ToolType } from "@app/hooks/tools/shared/useToolOperation";
|
||||
|
||||
/** Classify-and-tag takes no user parameters — it only needs the file. */
|
||||
export type ClassifyParameters = Record<string, never>;
|
||||
|
||||
export const defaultParameters: ClassifyParameters = {};
|
||||
|
||||
// Static function shared by the registry/automation executor. The backend reads
|
||||
// only the file: it classifies via the AI engine and writes the result into the
|
||||
// StirlingPDFClassification metadata field.
|
||||
export const buildClassifyFormData = (
|
||||
_parameters: ClassifyParameters,
|
||||
file: File,
|
||||
): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
return formData;
|
||||
};
|
||||
|
||||
export const classifyOperationConfig = {
|
||||
toolType: ToolType.singleFile,
|
||||
buildFormData: buildClassifyFormData,
|
||||
operationType: "classify",
|
||||
endpoint: "/api/v1/ai/tools/classify-and-tag",
|
||||
multiFileEndpoint: false,
|
||||
defaultParameters,
|
||||
} as const;
|
||||
@@ -95,6 +95,16 @@ export interface PolicyRunView {
|
||||
createdAt: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations that run as policy pipeline steps but are NOT user-facing tools, so
|
||||
* they have no tool-registry entry and never appear in the tool picker. Maps the
|
||||
* operation id straight to its backend endpoint.
|
||||
*/
|
||||
const POLICY_OPERATION_ENDPOINTS: Record<string, string> = {
|
||||
// Document classification — dispatched only by the Classification policy.
|
||||
classify: "/api/v1/ai/tools/classify-and-tag",
|
||||
};
|
||||
|
||||
/** Resolve a frontend operation id to its backend tool endpoint path. */
|
||||
function resolveEndpoint(
|
||||
operation: string,
|
||||
@@ -103,10 +113,13 @@ function resolveEndpoint(
|
||||
): string | null {
|
||||
const config = toolRegistry[operation as keyof ToolRegistry]?.operationConfig;
|
||||
const endpoint = config?.endpoint;
|
||||
if (!endpoint) return null;
|
||||
const resolved =
|
||||
typeof endpoint === "function" ? endpoint(parameters) : endpoint;
|
||||
return resolved ?? null;
|
||||
if (endpoint) {
|
||||
const resolved =
|
||||
typeof endpoint === "function" ? endpoint(parameters) : endpoint;
|
||||
if (resolved) return resolved;
|
||||
}
|
||||
// Policy-only operations have no registry entry; resolve them directly.
|
||||
return POLICY_OPERATION_ENDPOINTS[operation] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user