fred-capability-documents 4.4.3__py3-none-any.whl

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.
@@ -0,0 +1,382 @@
1
+ # Copyright Thales 2026
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ `DocumentSummarizeCapability` (RFC §3, §10) — on-demand document summarization.
17
+
18
+ Why this module exists:
19
+ - `summarize_document` used to be bundled inside `document_access`, but its
20
+ invocation is decided purely by the LLM from the tool docstring — there is
21
+ no query-shaped config condition (unlike `list_document_tree`'s
22
+ `team_documents`) that tells the runtime when the tool should even exist
23
+ for an agent. This capability is its own admin-gated, per-agent opt-in (an
24
+ agent selecting `document_access` does NOT get this tool for free) — the
25
+ admission control that governs it today.
26
+ - commonly paired with `document_access` (its `list_document_tree` /
27
+ `search_documents_using_vectorization` hits are the usual source of the
28
+ `document_uid` this tool's caller needs), but there is no runtime coupling:
29
+ the uid can equally come from the conversation's attached-files list.
30
+
31
+ `hitl_specs()` (RFC §5.4) gates `summarize_document` behind human approval by
32
+ default — defense in depth alongside admission control (`ADMIN_GATED` below):
33
+ admission decides whether an agent can select this tool at all, HITL decides
34
+ whether each individual call still needs a human's proceed/cancel. The gate
35
+ is configurable per agent instance via `require_confirmation` (default
36
+ `True`), not hardcoded — an admin who has already reviewed and trusts this
37
+ agent's usage can turn it off. (#2179, ReAct V2 HITL resume dead-ending in a
38
+ 409, blocked this until it was fixed — see `RUNTIME-EXECUTION-CONTRACT.md`.)
39
+
40
+ Doctrine (RFC §3.5, §3.8, §10) — same as `document_access`:
41
+ - the capability reaches the platform ONLY through the typed
42
+ `RuntimeServices.document_summarize` port; the per-turn binding and the raw
43
+ access token NEVER enter `CapabilityContext`
44
+ - the tool signature exposes ONLY LLM arguments; scope and identity reach the
45
+ tool through the middleware closure, never the tool schema
46
+
47
+ Identifier hygiene (hard rule, shared with `document_access`): the
48
+ `document_uid` argument is an internal working identifier for the agent's own
49
+ tool calls. The docstring instructs the model to NEVER repeat it to the end
50
+ user — answers refer to documents by display name only.
51
+ """
52
+
53
+ from __future__ import annotations
54
+
55
+ import time
56
+ from collections.abc import Sequence
57
+
58
+ from fred_sdk.contracts.capability import (
59
+ AgentCapability,
60
+ CapabilityContext,
61
+ CapabilityManifest,
62
+ EmptyModel,
63
+ HitlGateRequest,
64
+ HitlSpec,
65
+ )
66
+ from fred_sdk.contracts.context import (
67
+ ToolContentBlock,
68
+ ToolContentKind,
69
+ ToolInvocationResult,
70
+ )
71
+ from fred_sdk.contracts.models import FieldSpec, UIHints
72
+ from fred_sdk.contracts.runtime import (
73
+ DocumentScopeRefusedError,
74
+ DocumentSummaryResult,
75
+ unwrap_run_stop_error,
76
+ )
77
+ from langchain_core.tools import BaseTool, tool
78
+ from pydantic import BaseModel, Field
79
+
80
+ from fred_capability_documents.document_read_common import document_scope_refusal
81
+
82
+ _KF_SERVICE = "Knowledge Flow"
83
+
84
+ # Built-in default summary length when neither the caller (the LLM) nor the
85
+ # capability config specifies one.
86
+ DEFAULT_SUMMARIZE_MAX_CHARS = 5000
87
+ # Wire bounds of the Knowledge Flow endpoint's `max_chars` validation — clamp
88
+ # client-side so an out-of-range LLM value degrades gracefully instead of 422ing.
89
+ _SUMMARIZE_MAX_CHARS_BOUNDS = (200, 20_000)
90
+
91
+
92
+ def _clamp(value: int, bounds: tuple[int, int]) -> int:
93
+ low, high = bounds
94
+ return max(low, min(value, high))
95
+
96
+
97
+ def resolve_summarize_max_chars(cap: int | None, requested: int | None) -> int:
98
+ """
99
+ Resolve the effective summary length from the configured cap and the
100
+ caller's request.
101
+
102
+ The per-agent cap (`summarize_max_chars` config) is both the default (when
103
+ the caller asks for nothing) and a hard upper bound on whatever the caller
104
+ requests; without one, the built-in default applies and the caller's
105
+ request is honored verbatim (within wire bounds).
106
+ """
107
+
108
+ default = cap if cap is not None else DEFAULT_SUMMARIZE_MAX_CHARS
109
+ effective = requested if requested is not None else default
110
+ if cap is not None:
111
+ effective = min(effective, cap)
112
+ return _clamp(effective, _SUMMARIZE_MAX_CHARS_BOUNDS)
113
+
114
+
115
+ def _document_tool_failure(
116
+ *,
117
+ tool_ref: str,
118
+ action: str,
119
+ exc: Exception,
120
+ elapsed_s: float,
121
+ document_uid: str | None = None,
122
+ ) -> tuple[str, ToolInvocationResult]:
123
+ """Turn any document tool-call failure into a non-empty, actionable error
124
+ message plus an ``is_error=True`` artifact.
125
+
126
+ The v2 ReAct runtime surfaces ``ToolInvocationResult.is_error`` directly to
127
+ the user (and suppresses LLM hallucination), so a failing tool MUST return
128
+ such a result instead of raising — a raised exception is re-raised by the
129
+ default ``ToolNode`` handler, which leaves the tool call pending in the
130
+ trace and yields an empty error detail to the UI.
131
+
132
+ Transport detail (timeout, HTTP status) arrives via the SDK-typed
133
+ `DocumentPortCallError` attributes the adapters stamp — this module never
134
+ imports the adapter's HTTP stack.
135
+ """
136
+
137
+ err_type = type(exc).__name__
138
+ raw = str(exc).strip()
139
+ timed_out = bool(getattr(exc, "timed_out", False))
140
+ status_code = getattr(exc, "status_code", None)
141
+
142
+ if timed_out:
143
+ cause = f"the {_KF_SERVICE} service timed out after {elapsed_s:.0f}s"
144
+ elif status_code is not None:
145
+ cause = f"the {_KF_SERVICE} service returned HTTP {status_code}"
146
+ else:
147
+ cause = f"the {_KF_SERVICE} service call failed after {elapsed_s:.0f}s"
148
+
149
+ target = f" (document_uid={document_uid})" if document_uid else ""
150
+ detail = f": {raw}" if raw else ""
151
+ message = f"Could not {action}{target}: {cause} [{err_type}{detail}]."
152
+ return message, ToolInvocationResult(
153
+ tool_ref=tool_ref,
154
+ is_error=True,
155
+ blocks=(ToolContentBlock(kind=ToolContentKind.TEXT, text=message),),
156
+ )
157
+
158
+
159
+ class DocumentSummarizeConfig(BaseModel):
160
+ """
161
+ Agent-creation / stored config of the document-summarize capability
162
+ (RFC §3.2, #2177).
163
+ """
164
+
165
+ # Per-agent default AND hard cap for summarize_document's summary length
166
+ # (chars). None = built-in default, caller's request honored verbatim.
167
+ summarize_max_chars: int | None = Field(default=None, ge=200, le=20_000)
168
+ # Whether summarize_document pauses for human proceed/cancel before each
169
+ # call (RFC §5.4). Defaults to on — an admin who trusts this agent's
170
+ # usage can turn it off per instance; see `hitl_specs()`.
171
+ require_confirmation: bool = True
172
+
173
+
174
+ class DocumentSummarizeCapability(
175
+ AgentCapability[DocumentSummarizeConfig, DocumentSummarizeConfig, EmptyModel]
176
+ ):
177
+ """
178
+ On-demand document summarization, wired through the `document_summarize`
179
+ port. Single tool, no chat controls, no turn options — see the module
180
+ docstring for the admission/execution split with `document_access`.
181
+ """
182
+
183
+ manifest = CapabilityManifest(
184
+ id="document_summarize",
185
+ # Pre-GA: version stays 0.1.0 while the platform has not shipped —
186
+ # config-surface changes land without bumps.
187
+ version="0.1.0",
188
+ name="capability.document_summarize.name",
189
+ description="capability.document_summarize.description",
190
+ icon="summarize",
191
+ config_fields=[
192
+ FieldSpec(
193
+ key="require_confirmation",
194
+ type="boolean",
195
+ title="capability.document_summarize.fields.require_confirmation.title",
196
+ description="capability.document_summarize.fields.require_confirmation.description",
197
+ default=True,
198
+ ui=UIHints(group="safety"),
199
+ ),
200
+ FieldSpec(
201
+ key="summarize_max_chars",
202
+ type="integer",
203
+ title="capability.document_summarize.fields.summarize_max_chars.title",
204
+ description="capability.document_summarize.fields.summarize_max_chars.description",
205
+ min=200,
206
+ max=20_000,
207
+ ui=UIHints(group="retrieval", advanced=True),
208
+ ),
209
+ ],
210
+ # No new chat part / side panel / router / owned table.
211
+ # team_scope intentionally left at the class default (ADMIN_GATED,
212
+ # RFC §7, §8.3): unlike document_access's baseline search/tree, this
213
+ # tool has no config-shaped trigger a user can reason about — a team
214
+ # admin must explicitly enable it before any agent in that team can
215
+ # even select it.
216
+ )
217
+ ConfigModel = DocumentSummarizeConfig
218
+
219
+ def tools(
220
+ self,
221
+ ctx: CapabilityContext[DocumentSummarizeConfig, EmptyModel],
222
+ ) -> Sequence[BaseTool]:
223
+ """
224
+ Build the single summarize tool, bound to the turn's typed context
225
+ (RFC §3.2, §5). `AgentCapability.middleware()`'s default wraps this
226
+ for `create_agent()`; no ReAct-loop-specific hook is needed.
227
+
228
+ Return-convention note:
229
+ kept as `@tool(..., response_format="content_and_artifact")` returning
230
+ a `(content, ToolInvocationResult)` tuple — see `document_access`'s
231
+ `tools()` docstring for the full rationale; identical constraint here.
232
+ """
233
+
234
+ config = ctx.config
235
+ services = ctx.services
236
+ summarize_cap = config.summarize_max_chars
237
+
238
+ @tool("summarize_document", response_format="content_and_artifact")
239
+ async def summarize_document(
240
+ document_uid: str,
241
+ instruction: str | None = None,
242
+ max_chars: int | None = None,
243
+ ) -> tuple[str, ToolInvocationResult]:
244
+ """Generate a fresh, on-demand summary of one document by its uid.
245
+
246
+ Use this when you need to understand a document's content in depth —
247
+ e.g. to decide whether it's relevant, or to extract specific
248
+ information — without pulling its full text into your own context. A
249
+ fresh model reads the whole document (using map-reduce for large
250
+ documents) and returns just the summary.
251
+
252
+ `document_uid` MUST be the document's opaque uid, not its name or
253
+ title. Get it from a prior search_documents_using_vectorization
254
+ hit's 'uid' field, from list_document_tree (the value shown in
255
+ '[...]' after each document name), or from the conversation's
256
+ attached-files list (the bracketed value after the file name). If
257
+ you only know a document's name, resolve its uid with one of those
258
+ first — never pass the name here. The uid is an internal working
259
+ identifier for YOUR tool calls only: NEVER repeat it in your answer
260
+ to the user — always refer to the document by its display name.
261
+
262
+ Pass `instruction` to steer the summary: focus area, what to look
263
+ for, audience, tone, desired length — e.g. "focus on financial risks
264
+ and list every action item". Without it, you get a generic abstract.
265
+
266
+ `max_chars` bounds the returned summary length; raise it for a more
267
+ detailed summary, lower it for a terse one. Leave it unset to use
268
+ the agent's configured default. The agent may also impose a hard
269
+ maximum, in which case a larger request is clamped down to it.
270
+ """
271
+
272
+ port = services.document_summarize
273
+ if port is None:
274
+ raise RuntimeError(
275
+ "document_summarize: RuntimeServices.document_summarize is "
276
+ "not available on this execution path."
277
+ )
278
+
279
+ effective_max_chars = resolve_summarize_max_chars(summarize_cap, max_chars)
280
+ started = time.monotonic()
281
+ try:
282
+ result: DocumentSummaryResult = await port.summarize(
283
+ document_uid,
284
+ instruction=instruction,
285
+ max_chars=effective_max_chars,
286
+ )
287
+ except DocumentScopeRefusedError as exc:
288
+ return document_scope_refusal(
289
+ tool_ref="summarize_document",
290
+ action="summarize the document",
291
+ exc=exc,
292
+ )
293
+ except Exception as exc:
294
+ run_stop = unwrap_run_stop_error(exc)
295
+ if run_stop is not None:
296
+ raise run_stop from None
297
+ message, artifact = _document_tool_failure(
298
+ tool_ref="summarize_document",
299
+ action="summarize the document",
300
+ exc=exc,
301
+ elapsed_s=time.monotonic() - started,
302
+ document_uid=document_uid,
303
+ )
304
+ # 403/404 almost always means the model passed something that
305
+ # is not a document uid — a file NAME, a stale/foreign uid, or
306
+ # a FOLDER's tag id from a list_document_tree folder line
307
+ # (observed live, issue #2244) — the backend fails closed on
308
+ # unknown resources. Tell the model how to recover instead of
309
+ # letting it give up and echo the error.
310
+ if getattr(exc, "status_code", None) in (403, 404):
311
+ message += (
312
+ " Likely cause: document_uid was not a document's "
313
+ "opaque uid. If you passed a file name, resolve the "
314
+ "uid first: it is in the conversation's attached-files "
315
+ "list (the bracketed value after the file name), in a "
316
+ "search hit's 'uid' field, or on a DOCUMENT line of "
317
+ "list_document_tree. If you took the id from a FOLDER "
318
+ "line (it ends with '/', id shown as [folder:...]), "
319
+ "that is a folder id, not a document — summarize each "
320
+ "document listed under that folder instead. Then call "
321
+ "summarize_document again with a real document uid; "
322
+ "if other documents already summarized fine, continue "
323
+ "with those results. Do not repeat the uid to the "
324
+ "user."
325
+ )
326
+ # CAPAB-02: `_document_tool_failure` already baked the
327
+ # (shorter) pre-hint message into `artifact.blocks`; the
328
+ # recovery hint appended above must reach `blocks` too, or
329
+ # a Graph agent — which keeps only the artifact half of
330
+ # this return — loses exactly the guidance a model needs
331
+ # to self-correct and retry.
332
+ artifact = artifact.model_copy(
333
+ update={
334
+ "blocks": (
335
+ ToolContentBlock(
336
+ kind=ToolContentKind.TEXT, text=message
337
+ ),
338
+ )
339
+ }
340
+ )
341
+ return message, artifact
342
+ # `blocks` carries the same summary text as `content` (CAPAB-02):
343
+ # a Graph agent's plain-dict invocation keeps only the artifact
344
+ # half of a `content_and_artifact` return.
345
+ artifact = ToolInvocationResult(
346
+ tool_ref="summarize_document",
347
+ blocks=(
348
+ ToolContentBlock(kind=ToolContentKind.TEXT, text=result.summary),
349
+ ),
350
+ )
351
+ return result.summary, artifact
352
+
353
+ return [summarize_document]
354
+
355
+ def hitl_specs(self) -> Sequence[HitlSpec]:
356
+ """
357
+ `summarize_document` is gated by default, per instance configurable
358
+ (#2177) — `require=False` defers to `_confirmation_required` instead
359
+ of hardcoding the decision, the same `when`-predicate mechanism
360
+ `document_access` already relies on for its own conditional scope
361
+ fields (RFC §5.4). The predicate reads the resolved instance config
362
+ fresh at gate time (`request.context.config`), so it always reflects
363
+ the CURRENT `require_confirmation` value, not whatever was true when
364
+ `hitl_specs()` itself was called (assembly time, no per-turn context
365
+ yet).
366
+ """
367
+
368
+ return [
369
+ HitlSpec(
370
+ tool="summarize_document",
371
+ require=False,
372
+ when=_confirmation_required,
373
+ )
374
+ ]
375
+
376
+
377
+ def _confirmation_required(request: HitlGateRequest) -> bool:
378
+ """Whether this agent instance still wants a human's proceed/cancel
379
+ before `summarize_document` runs — the resolved `require_confirmation`
380
+ config value (default `True`, see `DocumentSummarizeConfig`)."""
381
+
382
+ return bool(request.context.config.require_confirmation)
@@ -0,0 +1,27 @@
1
+ # Copyright Thales 2026
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ `DocumentVerbatimCapability` (DOCREAD-01) — verbatim, paginated document read.
17
+
18
+ Installing fred-capability-documents registers it via the `fred.capabilities` entry point
19
+ (`document_verbatim`). Pairs with `document_extract` over the shared
20
+ `document_markdown` port; see `document_read_common`.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from .capability import DocumentVerbatimCapability
26
+
27
+ __all__ = ["DocumentVerbatimCapability"]
@@ -0,0 +1,128 @@
1
+ # Copyright Thales 2026
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ `DocumentVerbatimCapability` (DOCREAD-01) — read a document's exact text
17
+ verbatim, one bounded page at a time, through the `document_markdown` port.
18
+
19
+ Half of the document-reading pair (see `document_read_common`). This capability
20
+ answers positional/literal questions ("what does the first paragraph say?",
21
+ "read section 3") — distinct from `document_extract` (exhaustive enumeration by
22
+ criterion) and `document_summarize` (a lossy overview). All three can coexist on
23
+ one agent; each tool's docstring draws the boundary so the model picks the right
24
+ one.
25
+
26
+ Installing fred-capability-documents registers it via the `fred.capabilities` entry point
27
+ (`document_verbatim`); it is `ADMIN_GATED` (class default), a per-agent opt-in a
28
+ team admin must enable.
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ from collections.abc import Sequence
34
+
35
+ from fred_sdk.contracts.capability import (
36
+ AgentCapability,
37
+ CapabilityContext,
38
+ CapabilityManifest,
39
+ EmptyModel,
40
+ )
41
+ from fred_sdk.contracts.context import ToolInvocationResult
42
+ from fred_sdk.contracts.models import FieldSpec, UIHints
43
+ from langchain_core.tools import BaseTool, tool
44
+
45
+ from fred_capability_documents.document_read_common import (
46
+ DocumentReadConfig,
47
+ read_document_page,
48
+ resolve_page_max_chars,
49
+ )
50
+
51
+
52
+ class DocumentVerbatimCapability(
53
+ AgentCapability[DocumentReadConfig, DocumentReadConfig, EmptyModel]
54
+ ):
55
+ """Verbatim, paginated document read. Single tool, no chat controls, no turn
56
+ options, no HITL (read-only)."""
57
+
58
+ manifest = CapabilityManifest(
59
+ id="document_verbatim",
60
+ # Pre-GA: version stays 0.1.0 while the platform has not shipped.
61
+ version="0.1.0",
62
+ name="capability.document_verbatim.name",
63
+ description="capability.document_verbatim.description",
64
+ icon="description",
65
+ config_fields=[
66
+ FieldSpec(
67
+ key="page_max_chars",
68
+ type="integer",
69
+ title="capability.document_verbatim.fields.page_max_chars.title",
70
+ description="capability.document_verbatim.fields.page_max_chars.description",
71
+ min=200,
72
+ max=50_000,
73
+ ui=UIHints(group="retrieval", advanced=True),
74
+ ),
75
+ ],
76
+ # team_scope left at the class default (ADMIN_GATED).
77
+ )
78
+ ConfigModel = DocumentReadConfig
79
+
80
+ def tools(
81
+ self,
82
+ ctx: CapabilityContext[DocumentReadConfig, EmptyModel],
83
+ ) -> Sequence[BaseTool]:
84
+ config = ctx.config
85
+ services = ctx.services
86
+ page_cap = config.page_max_chars
87
+
88
+ @tool("read_document", response_format="content_and_artifact")
89
+ async def read_document(
90
+ document_uid: str,
91
+ offset: int = 0,
92
+ max_chars: int | None = None,
93
+ ) -> tuple[str, ToolInvocationResult]:
94
+ """Read a document's exact text VERBATIM, one page at a time.
95
+
96
+ Use this to see what a document literally says at a given position —
97
+ e.g. "what does the first paragraph say?", "read the introduction",
98
+ "show me section 3" — or to read a whole short document. Returns the
99
+ document's text unchanged, NOT a summary.
100
+
101
+ When to use a different tool instead:
102
+ - for a short, lossy overview of the whole document → summarize_document;
103
+ - to enumerate EVERY item matching a criterion across the whole
104
+ document ("all the requirements") → extract_from_document.
105
+
106
+ `document_uid` MUST be the document's opaque uid, not its name — get
107
+ it from a search hit's 'uid', the document tree, or the
108
+ conversation's attached-files list. The uid is an internal working
109
+ identifier for YOUR tool calls only: NEVER repeat it in your answer;
110
+ always refer to the document by its display name.
111
+
112
+ `offset` is the character position to start from (0 = the very
113
+ beginning). `max_chars` bounds this page (leave unset for the agent's
114
+ default). If the returned result says more text remains, call again
115
+ with the next offset it gives you to keep reading.
116
+ """
117
+
118
+ effective = resolve_page_max_chars(page_cap, max_chars)
119
+ return await read_document_page(
120
+ port=services.document_markdown,
121
+ tool_ref="read_document",
122
+ document_uid=document_uid,
123
+ offset=offset,
124
+ max_chars=effective,
125
+ exhaustive=False,
126
+ )
127
+
128
+ return [read_document]
File without changes
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.4
2
+ Name: fred-capability-documents
3
+ Version: 4.4.3
4
+ Summary: Fred agent capabilities over the Knowledge Flow document ports: summarize, similarity, label search, extract, verbatim read.
5
+ Author-email: Thales <noreply@thalesgroup.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://site.fredlab.dev
8
+ Project-URL: Repository, https://github.com/ThalesGroup/fred
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: <3.13,>=3.12
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: fred-core>=4.4.3
16
+ Requires-Dist: fred-sdk[agents]>=4.4.3
17
+ Requires-Dist: pydantic<3.0.0,>=2.7.0
18
+ Requires-Dist: langchain-core>=0.3.0
19
+ Provides-Extra: dev
20
+ Requires-Dist: bandit>=1.8.6; extra == "dev"
21
+ Requires-Dist: basedpyright==1.31.0; extra == "dev"
22
+ Requires-Dist: detect-secrets>=1.5.0; extra == "dev"
23
+ Requires-Dist: pytest>=8.4.2; extra == "dev"
24
+ Requires-Dist: pytest-asyncio>=1.2.0; extra == "dev"
25
+ Requires-Dist: pytest-cov>=6.2.1; extra == "dev"
26
+ Requires-Dist: pytest-socket>=0.7.0; extra == "dev"
27
+ Requires-Dist: ruff<0.16,>=0.15.22; extra == "dev"
28
+
29
+ # fred-capability-documents
30
+
31
+ Fred agent capabilities over the Knowledge Flow document ports. One package,
32
+ one `fred.capabilities` entry point per capability, each admin-gated and
33
+ independently grantable by a team admin.
34
+
35
+ ## Capabilities
36
+
37
+ - **`document_summarize`** — on-demand summary of one document
38
+ (`RuntimeServices.document_summarize`).
39
+ - **`document_similarity`** — targeted document-to-document comparison
40
+ (`RuntimeServices.document_similarity`).
41
+ - **`document_label_search`** — exhaustive, paginated resolution of a
42
+ business label to documents (`RuntimeServices.document_tree`).
43
+ - **`document_verbatim`** — verbatim, paginated read of one document
44
+ (`RuntimeServices.document_markdown`).
45
+ - **`document_extract`** — exhaustive extraction from one document
46
+ (`RuntimeServices.document_extraction`).
47
+
48
+ `document_read_common.py` holds what the reading pair and the error shaping
49
+ share. The capabilities reach the platform only through the typed fred-sdk
50
+ ports — no URL, credential or client lives here.
51
+
52
+ ## Registration
53
+
54
+ Installing this package *is* the registration: the fred-agents pod
55
+ auto-discovers each capability at boot via the `fred.capabilities` entry
56
+ points declared in `pyproject.toml`. Nothing else to wire.
57
+
58
+ Authoring guide: `docs/swift/capabilities/AUTHORING.md`.
@@ -0,0 +1,18 @@
1
+ fred_capability_documents/__init__.py,sha256=udb_Xsa7gosduxzU9BcG3YSYR4u5KWoATb3CQs-lTtA,888
2
+ fred_capability_documents/document_read_common.py,sha256=5fZ-G2RyRCrR47nUTNHiHf7zM55rwobobUQiBXqySqg,10527
3
+ fred_capability_documents/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ fred_capability_documents/document_extract/__init__.py,sha256=nv_AHyUNjE113JFs_6aB7c1TXSP47fedLBYgW4U7H6Y,1009
5
+ fred_capability_documents/document_extract/capability.py,sha256=VaFHh4cG1n_Cb_KAPVsy3YCl_u9qL3Z4I5jL7sMb2iQ,8582
6
+ fred_capability_documents/document_label_search/__init__.py,sha256=Cc11flcKLFpQ8ql3ledXzstx3DN5T3I_9zp7hbepz5U,1059
7
+ fred_capability_documents/document_label_search/capability.py,sha256=cOy4LIxE_LeAm375MEviHx0LKrVSeEpMMAQnAJJvaF0,10686
8
+ fred_capability_documents/document_similarity/__init__.py,sha256=5rhnxUqtobPeHGWIzdtWBLpoaPfIb7b6xmnnUGDb5uI,1034
9
+ fred_capability_documents/document_similarity/capability.py,sha256=jqXDeKzScDpAHEO77EJG5vIj_6n9kHFPD4AeSRXceBE,11852
10
+ fred_capability_documents/document_summarize/__init__.py,sha256=x1zu5IvC2i6HY_oplpbKXwrSqVPXhbOuiN5T4qFT6-g,1232
11
+ fred_capability_documents/document_summarize/capability.py,sha256=jF19DJrEgZMnqjqr3ruI2mDfBCPoz9JxjanhMuTk9x8,17342
12
+ fred_capability_documents/document_verbatim/__init__.py,sha256=hjC3-1jiX1_RibS_K7uo7qTGfCM8esuWTCUf9qDyS2A,1004
13
+ fred_capability_documents/document_verbatim/capability.py,sha256=UArZNEW9kXrxI8XUQId6vSm_c10CHeHnNxVzRvijkds,5149
14
+ fred_capability_documents-4.4.3.dist-info/METADATA,sha256=xZC2rVLoyL2NJ9bjoLXkMYp7z6CXv2LhIsXMY1nkY00,2530
15
+ fred_capability_documents-4.4.3.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
16
+ fred_capability_documents-4.4.3.dist-info/entry_points.txt,sha256=BsOBCx2hpgmrOsuRNlTQ4ZRMOWmLD6AZU-2E3DZIHng,492
17
+ fred_capability_documents-4.4.3.dist-info/top_level.txt,sha256=5pzhsSaq21Qyqzp9Hlv95AjRZvR1_0Pd_OB9UQx71Zw,26
18
+ fred_capability_documents-4.4.3.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,6 @@
1
+ [fred.capabilities]
2
+ document_extract = fred_capability_documents.document_extract:DocumentExtractCapability
3
+ document_label_search = fred_capability_documents.document_label_search:DocumentLabelSearchCapability
4
+ document_similarity = fred_capability_documents.document_similarity:DocumentSimilarityCapability
5
+ document_summarize = fred_capability_documents.document_summarize:DocumentSummarizeCapability
6
+ document_verbatim = fred_capability_documents.document_verbatim:DocumentVerbatimCapability
@@ -0,0 +1 @@
1
+ fred_capability_documents