@frontera-sdk/cli 1.52.39 → 1.52.41
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 +9 -0
- package/package.json +6 -4
- package/src/adopt.ts +6 -2
- package/src/api/apps-api.ts +86 -4
- package/src/api/blueprint-authoring-api.ts +35 -11
- package/src/api/dataset-api.ts +29 -0
- package/src/api/governed-action-api.ts +90 -2
- package/src/api/platform-api.ts +87 -2
- package/src/api/workflow-api.ts +33 -2
- package/src/app-contract.ts +156 -0
- package/src/app-lock.ts +125 -0
- package/src/args.ts +14 -3
- package/src/auth-verify.ts +10 -0
- package/src/automation-template.ts +12 -1
- package/src/blueprint/action-rules.ts +516 -0
- package/src/blueprint/action-semantic-fit.ts +205 -0
- package/src/blueprint/compile.ts +51 -2
- package/src/blueprint/diff.ts +34 -2
- package/src/blueprint/metric-query.ts +215 -0
- package/src/blueprint/metric-rules.ts +122 -0
- package/src/blueprint/object-sets.ts +116 -0
- package/src/blueprint/ontology-edit-plan.ts +49 -5
- package/src/blueprint/projection.ts +24 -1
- package/src/blueprint/scaffold.ts +84 -42
- package/src/commands/action/available.ts +1 -1
- package/src/commands/action/criteria-refusal.ts +84 -0
- package/src/commands/action/decide.ts +5 -2
- package/src/commands/action/deploy.ts +13 -4
- package/src/commands/action/list.ts +134 -19
- package/src/commands/action/requests.ts +34 -6
- package/src/commands/action/submit.ts +28 -13
- package/src/commands/agent/draft-changes.ts +1 -1
- package/src/commands/agent/index-commands.ts +69 -7
- package/src/commands/agent/resolve.ts +2 -0
- package/src/commands/app/checks.ts +44 -0
- package/src/commands/app/deploy.ts +243 -60
- package/src/commands/app/deployments.ts +97 -0
- package/src/commands/app/dev.ts +103 -11
- package/src/commands/app/init.ts +36 -3
- package/src/commands/app/promote.ts +45 -19
- package/src/commands/app/pull.ts +3 -1
- package/src/commands/app/rollback.ts +46 -0
- package/src/commands/app/sdk.ts +54 -8
- package/src/commands/app/unpin.ts +27 -0
- package/src/commands/app/versions.ts +1 -1
- package/src/commands/automation/bindings.ts +4 -2
- package/src/commands/automation/build-entry.ts +4 -1
- package/src/commands/automation/index-commands.ts +3 -1
- package/src/commands/automation/pull.ts +6 -1
- package/src/commands/automation/run.ts +34 -9
- package/src/commands/blueprint/bind.ts +2 -1
- package/src/commands/blueprint/declarative.ts +332 -32
- package/src/commands/blueprint/editable.ts +3 -3
- package/src/commands/blueprint/get.ts +6 -2
- package/src/commands/blueprint/grants.ts +64 -10
- package/src/commands/blueprint/metric.ts +108 -0
- package/src/commands/blueprint/object-sets.ts +71 -0
- package/src/commands/blueprint/query.ts +155 -31
- package/src/commands/dataset/index-commands.ts +156 -7
- package/src/commands/knowledge/index-commands.ts +122 -20
- package/src/commands/local/check.ts +657 -44
- package/src/commands/local/data.ts +33 -12
- package/src/commands/local/dev.ts +876 -89
- package/src/commands/local/docs-mcp.ts +10 -18
- package/src/commands/local/index-commands.ts +300 -63
- package/src/commands/local/init.ts +18 -5
- package/src/commands/local/key.ts +0 -3
- package/src/commands/local/providers.ts +0 -7
- package/src/commands/local/remove.ts +116 -0
- package/src/commands/local/schema.ts +3 -4
- package/src/commands/local/sdk-refresh.ts +59 -0
- package/src/commands/local/snapshot.ts +100 -0
- package/src/commands/local/sync-request.ts +321 -14
- package/src/commands/local/sync.ts +103 -6
- package/src/commands/mcp/serve.ts +34 -0
- package/src/commands/registry.ts +54 -10
- package/src/commands/types.ts +29 -0
- package/src/commands/workflow/archive.ts +46 -0
- package/src/commands/workflow/get.ts +2 -1
- package/src/commands/workflow/index-commands.ts +5 -0
- package/src/commands/workflow/push.ts +49 -2
- package/src/commands/workflow/run.ts +65 -7
- package/src/commands/workflow/runs.ts +9 -6
- package/src/commands/workflow/webhook-test.ts +166 -0
- package/src/config.ts +43 -6
- package/src/dev-broker.ts +52 -0
- package/src/exit.ts +103 -4
- package/src/flag-help.ts +77 -17
- package/src/forge/claude-commands.ts +11 -6
- package/src/forge/claude-skills.ts +4 -4
- package/src/forge/touches.ts +15 -12
- package/src/function-outside-imports.ts +89 -0
- package/src/harness.ts +42 -24
- package/src/heal.ts +113 -2
- package/src/kit.ts +1 -1
- package/src/local/fix-words.ts +12 -0
- package/src/local/function-bundle-recovery.ts +775 -0
- package/src/local/local-actions.ts +103 -10
- package/src/local/local-agent-action-grants.ts +210 -0
- package/src/local/local-agent-checks.ts +232 -0
- package/src/local/local-agent-grants.ts +29 -7
- package/src/local/local-agent-lean-plugins.ts +68 -0
- package/src/local/local-agent-missing-tools.ts +68 -0
- package/src/local/local-agent-name.ts +27 -0
- package/src/local/local-app-code.ts +191 -0
- package/src/local/local-app-dev-files.ts +186 -0
- package/src/local/local-app-dev-session.ts +88 -0
- package/src/local/local-app-lock-install.ts +114 -0
- package/src/local/local-app-pulled.ts +167 -0
- package/src/local/local-app-restore.ts +111 -0
- package/src/local/local-app-runtime.ts +68 -0
- package/src/local/local-app-sdk-paths.ts +149 -0
- package/src/local/local-app-sdk.ts +509 -0
- package/src/local/local-applied.ts +212 -22
- package/src/local/local-apply-history.ts +84 -0
- package/src/local/local-apply-summary.ts +86 -0
- package/src/local/local-apply-watchdog.ts +95 -0
- package/src/local/local-apps.ts +181 -8
- package/src/local/local-blueprint-errors.ts +198 -0
- package/src/local/local-blueprint-outline.ts +31 -12
- package/src/local/local-blueprint-schemas.ts +582 -0
- package/src/local/local-build-inputs.ts +48 -0
- package/src/local/local-build-summary.ts +495 -28
- package/src/local/local-case-evidence.ts +120 -0
- package/src/local/local-case-not-run.ts +153 -0
- package/src/local/local-chat-apps.ts +93 -16
- package/src/local/local-check-inherited.ts +83 -0
- package/src/local/local-cities.ts +89 -0
- package/src/local/local-component-health.ts +119 -0
- package/src/local/local-control.ts +34 -7
- package/src/local/local-db-snapshot.ts +348 -0
- package/src/local/local-dev-references.ts +347 -36
- package/src/local/local-dev-sync.ts +141 -12
- package/src/local/local-docker.ts +35 -1
- package/src/local/local-docs-search.ts +1 -1
- package/src/local/local-docs.ts +281 -2
- package/src/local/local-empty-workflows.ts +92 -0
- package/src/local/local-env.ts +16 -1
- package/src/local/local-file-checks.ts +104 -0
- package/src/local/local-function-ids.ts +141 -0
- package/src/local/local-function-recovery.ts +141 -0
- package/src/local/local-function-state.ts +87 -0
- package/src/local/local-keys.ts +7 -5
- package/src/local/local-knowledge-documents.ts +1 -1
- package/src/local/local-knowledge-ingestion.ts +225 -0
- package/src/local/local-knowledge-uploads.ts +217 -0
- package/src/local/local-lessons.ts +1 -1
- package/src/local/local-library.ts +1 -1
- package/src/local/local-media-placeholders.ts +182 -0
- package/src/local/local-media-sets.ts +90 -10
- package/src/local/local-model-parameters.ts +89 -0
- package/src/local/local-object-sets.ts +18 -6
- package/src/local/local-operating.ts +35 -1
- package/src/local/local-org-settings.ts +206 -8
- package/src/local/local-orphans.ts +321 -0
- package/src/local/local-personas.ts +296 -0
- package/src/local/local-portability.ts +143 -18
- package/src/local/local-ports.ts +99 -7
- package/src/local/local-project-notices.ts +234 -0
- package/src/local/local-project-secrets.ts +133 -0
- package/src/local/local-project.ts +12 -0
- package/src/local/local-provider-refusal.ts +66 -0
- package/src/local/local-request-evidence.ts +112 -0
- package/src/local/local-runtime-health.ts +123 -0
- package/src/local/local-runtime-history.ts +50 -0
- package/src/local/local-runtime-target.ts +42 -0
- package/src/local/local-sample-data.ts +141 -0
- package/src/local/local-sample-remake.ts +138 -0
- package/src/local/local-scaffold.ts +336 -53
- package/src/local/local-schema-check.ts +148 -0
- package/src/local/local-schemas.ts +742 -25
- package/src/local/local-secret-carry.ts +107 -0
- package/src/local/local-secrets.ts +41 -11
- package/src/local/local-seed.ts +102 -26
- package/src/local/local-stand-ins.ts +3 -3
- package/src/local/local-state.ts +43 -2
- package/src/local/local-studio-server.ts +170 -7
- package/src/local/local-supervisor.ts +44 -6
- package/src/local/local-sync-merge.ts +1 -1
- package/src/local/local-sync-names.ts +2 -0
- package/src/local/local-sync-plan.ts +19 -8
- package/src/local/local-sync-push.ts +15 -12
- package/src/local/local-sync-refs.ts +49 -3
- package/src/local/local-sync-remote.ts +349 -38
- package/src/local/local-sync-snapshot.ts +18 -13
- package/src/local/local-synthetic-data.ts +2116 -99
- package/src/local/local-test-baseline.ts +113 -0
- package/src/local/local-test-cases.ts +76 -1
- package/src/local/local-test-runner.ts +582 -91
- package/src/local/local-test-runs.ts +13 -5
- package/src/local/local-vendored-sdk.ts +183 -0
- package/src/local/local-workflow-state.ts +16 -3
- package/src/local/local-workflow-tests.ts +482 -0
- package/src/local/local-workspace-grants.ts +81 -0
- package/src/main.ts +50 -9
- package/src/mcp/a11y-scan.ts +55 -0
- package/src/mcp/browser/ax-snapshot.ts +181 -0
- package/src/mcp/browser/credentials.ts +78 -0
- package/src/mcp/browser/frames.ts +336 -0
- package/src/mcp/browser/headless-session.ts +413 -0
- package/src/mcp/browser/headless-tab.ts +575 -0
- package/src/mcp/browser/keys.ts +70 -0
- package/src/mcp/browser/page-scripts.ts +129 -0
- package/src/mcp/browser/wait.ts +73 -0
- package/src/mcp/forge-link.ts +126 -0
- package/src/mcp/headless.ts +199 -0
- package/src/mcp/mcp-apps.ts +435 -0
- package/src/mcp/mcp-chat.ts +226 -0
- package/src/mcp/mcp-cli.ts +53 -0
- package/src/mcp/mcp-protocol.ts +122 -0
- package/src/mcp/mcp-runtime.ts +113 -0
- package/src/mcp/mcp-server.ts +108 -0
- package/src/mcp/mcp-traces.ts +409 -0
- package/src/mcp/page-observation.ts +193 -0
- package/src/mcp/tools/agent-tools.ts +700 -0
- package/src/mcp/tools/app-tools.ts +241 -0
- package/src/mcp/tools/browser-tools.ts +310 -0
- package/src/mcp/tools/docs-tools.ts +32 -0
- package/src/mcp/tools/project-tools.ts +205 -0
- package/src/mcp/tools/test-tools.ts +339 -0
- package/src/mcp/tools/workflow-tools.ts +611 -0
- package/src/output.ts +1 -1
- package/src/pack.ts +8 -3
- package/src/packaging.ts +1 -1
- package/src/project-bootstrap.ts +107 -4
- package/src/project-context.ts +18 -1
- package/src/project.ts +27 -2
- package/src/provenance.ts +25 -0
- package/src/render-evidence.ts +65 -7
- package/src/scopes.ts +1 -1
- package/src/template.ts +14 -8
- package/src/templates/next-app-files.ts +35 -6
- package/src/templates/next-skills.ts +61 -27
- package/src/vendor/kit-assets.json +6 -6
- package/src/vendor/sdk-sources.json +17 -14
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { basename } from 'node:path'
|
|
2
2
|
|
|
3
|
-
import { PlatformApi } from '../../api/platform-api'
|
|
3
|
+
import { PlatformApi, type KnowledgeRetrieval } from '../../api/platform-api'
|
|
4
4
|
import { CliError, UsageError } from '../../errors'
|
|
5
|
+
import { DEFAULT_KNOWLEDGE_THRESHOLD, KEYLESS_KNOWLEDGE_THRESHOLD, KEYLESS_RETRIEVAL_NOTE, PLATFORM_DEFAULT_EMBEDDING, sameEmbedding, WIDENED_KNOWLEDGE_THRESHOLD } from '../../local/local-org-settings'
|
|
6
|
+
import { localRuntimeAt } from '../../local/local-runtime-target'
|
|
7
|
+
import { isLocalEmbeddings } from '../../local/local-seed'
|
|
5
8
|
import { table } from '../../table'
|
|
6
9
|
import { resolveAgentRef } from '../agent/resolve'
|
|
7
10
|
import { flagString, type Command } from '../types'
|
|
@@ -124,9 +127,11 @@ const get: Command = {
|
|
|
124
127
|
|
|
125
128
|
const client = new PlatformApi(ctx.apiUrl, ctx.token, ctx.workspaceId)
|
|
126
129
|
const base = await client.knowledgeBase(await resolveKnowledgeRef(client, ref))
|
|
130
|
+
// On the keyless local embeddings the threshold shown is the one set for them, and retrieval is approximate: said.
|
|
131
|
+
const local = (await keylessRetrieval(client, ctx.cwd, ctx.apiUrl)) ? { localRetrieval: keylessRetrievalInfo() } : {}
|
|
127
132
|
|
|
128
133
|
return {
|
|
129
|
-
data: base,
|
|
134
|
+
data: { ...base, ...local },
|
|
130
135
|
// Whatever the route returns, flattened. Naming the fields here would
|
|
131
136
|
// print "?" for every one the service renames, and the embedding model
|
|
132
137
|
// and chunker are exactly the fields a caller comes to this verb to read.
|
|
@@ -137,7 +142,7 @@ const get: Command = {
|
|
|
137
142
|
v === null || v === undefined ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v),
|
|
138
143
|
]),
|
|
139
144
|
[undefined, 70],
|
|
140
|
-
),
|
|
145
|
+
) + ('localRetrieval' in local ? `\n\nNote: ${KEYLESS_RETRIEVAL_NOTE}.` : ''),
|
|
141
146
|
}
|
|
142
147
|
},
|
|
143
148
|
}
|
|
@@ -160,9 +165,13 @@ const search: Command = {
|
|
|
160
165
|
],
|
|
161
166
|
flags: { 'top-k': 'string', threshold: 'string' },
|
|
162
167
|
summary: 'Search a knowledge base and show the chunks that come back',
|
|
168
|
+
details: [
|
|
169
|
+
'Without --threshold the base\'s own match threshold cuts the results, as an Agent\'s retrieval does. The cutoff is a maximum cosine distance from 0 to 2 (lower is stricter), while a score is higher-is-better: with vector scoring a score is 1 − distance / 2, so a 0.5 cutoff keeps scores above 0.75. The output says which cutoff applied.',
|
|
170
|
+
],
|
|
163
171
|
examples: [
|
|
164
172
|
'frontera knowledge search product-docs "how do refunds work"',
|
|
165
173
|
'frontera knowledge search product-docs "refund policy" --top-k 3 --json',
|
|
174
|
+
'frontera knowledge search product-docs "refund policy" --threshold 0.8',
|
|
166
175
|
],
|
|
167
176
|
},
|
|
168
177
|
async run(ctx) {
|
|
@@ -182,8 +191,9 @@ const search: Command = {
|
|
|
182
191
|
}
|
|
183
192
|
const thresholdRaw = flagString(ctx, 'threshold')
|
|
184
193
|
const threshold = thresholdRaw === undefined ? undefined : Number(thresholdRaw)
|
|
185
|
-
|
|
186
|
-
|
|
194
|
+
// A maximum cosine distance: 0 matches only identical text, 2 matches everything.
|
|
195
|
+
if (threshold !== undefined && (Number.isNaN(threshold) || threshold < 0 || threshold > 2)) {
|
|
196
|
+
throw new UsageError(`--threshold must be a cosine distance from 0 to 2, not "${thresholdRaw}"`, 'lower is stricter: try --threshold 0.8 to widen a search the base\'s own cutoff empties')
|
|
187
197
|
}
|
|
188
198
|
|
|
189
199
|
const client = new PlatformApi(ctx.apiUrl, ctx.token, ctx.workspaceId)
|
|
@@ -195,42 +205,104 @@ const search: Command = {
|
|
|
195
205
|
})
|
|
196
206
|
|
|
197
207
|
const chunks = result.results
|
|
208
|
+
const cutoff = cutoffLine(result.retrieval, threshold)
|
|
209
|
+
// On the keyless local embeddings: retrieval is approximate, said with what gives the platform's.
|
|
210
|
+
const keyless = await keylessRetrieval(client, ctx.cwd, ctx.apiUrl)
|
|
211
|
+
const keylessLine = keyless ? `\n Note: ${KEYLESS_RETRIEVAL_NOTE}.` : ''
|
|
212
|
+
if (keyless) Object.assign(result, { localRetrieval: keylessRetrievalInfo() })
|
|
198
213
|
if (chunks.length === 0) {
|
|
199
214
|
// The overwhelmingly common cause, and the one a caller cannot see from
|
|
200
215
|
// here: ingestion is asynchronous, so a base uploaded a minute ago is
|
|
201
216
|
// empty rather than broken.
|
|
217
|
+
// How near the search came, when the service says: the threshold that would show it.
|
|
218
|
+
const nearest = result.retrieval?.nearestDistance
|
|
219
|
+
const max = typeof result.retrieval?.maxDistance === 'number' ? result.retrieval.maxDistance : threshold
|
|
220
|
+
if (typeof nearest === 'number') {
|
|
221
|
+
// Only asked when it could matter: a near miss the widened local threshold would keep.
|
|
222
|
+
const embedding = !keyless && nearMissOfWidening(nearest) ? await client.embeddingSetting().catch(() => null) : null
|
|
223
|
+
const widening = embeddingNote(nearest, embedding, isLoopbackApi(ctx.apiUrl))
|
|
224
|
+
return {
|
|
225
|
+
data: result,
|
|
226
|
+
text: `No chunks matched: the nearest chunk is at distance ${nearest}, past the cutoff${max === undefined ? '' : ` of ${max}`}. \`--threshold\` above ${nearest} (up to 2) shows it; setting the base's \`similarityThreshold\` there changes what an Agent's retrieval keeps.\n ${cutoff}${widening ? `\n ${widening}` : ''}${keylessLine}`,
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (nearest === null) {
|
|
230
|
+
return {
|
|
231
|
+
data: result,
|
|
232
|
+
text: `No chunks matched: ${ref} has nothing searchable yet. \`frontera knowledge sources ${ref}\` lists its documents: none, or still \`processing\`.`,
|
|
233
|
+
}
|
|
234
|
+
}
|
|
202
235
|
return {
|
|
203
236
|
data: result,
|
|
204
237
|
text:
|
|
205
238
|
'No chunks matched.\n'
|
|
206
239
|
+ ` If the upload was recent, check \`frontera knowledge sources ${ref}\` — a source\n`
|
|
207
240
|
+ ' still `processing` is not searchable yet.\n'
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
+
|
|
211
|
-
? ` --threshold ${threshold} is a maximum cosine distance — raise it to widen the search.\n`
|
|
212
|
-
: ' The default cutoff is 0.9; pass a higher --threshold to widen the search.\n')
|
|
213
|
-
+ ' Otherwise the corpus may simply not cover this.',
|
|
241
|
+
+ ` ${cutoff} Raise --threshold (up to 2) to widen the search.\n`
|
|
242
|
+
+ ' Otherwise the corpus may simply not cover this.'
|
|
243
|
+
+ keylessLine,
|
|
214
244
|
}
|
|
215
245
|
}
|
|
216
246
|
|
|
247
|
+
// A distance beside each score when the service gives one: it is what the cutoff compares.
|
|
248
|
+
const distances = chunks.some((c) => typeof c.distance === 'number')
|
|
217
249
|
return {
|
|
218
250
|
data: result,
|
|
219
251
|
text: table(
|
|
220
|
-
['score', 'source', 'chunk'],
|
|
252
|
+
['score', ...(distances ? ['distance'] : []), 'source', 'chunk'],
|
|
221
253
|
chunks.map((c) => [
|
|
222
254
|
typeof c.score === 'number' ? c.score.toFixed(3) : String(c.score ?? ''),
|
|
255
|
+
...(distances ? [typeof c.distance === 'number' ? c.distance.toFixed(3) : ''] : []),
|
|
223
256
|
String(c.fileName ?? c.sourceId ?? ''),
|
|
224
257
|
String(c.content ?? c.text ?? '').replace(/\s+/g, ' ').trim(),
|
|
225
258
|
]),
|
|
226
|
-
[8, 30, 90],
|
|
227
|
-
)
|
|
259
|
+
distances ? [8, 9, 30, 90] : [8, 30, 90],
|
|
260
|
+
) + `\n\n${cutoff}${keylessLine}`,
|
|
228
261
|
}
|
|
229
262
|
},
|
|
230
263
|
}
|
|
231
264
|
|
|
265
|
+
/** Whether the nearest distance sits between the default threshold and the one a local runtime widens to. */
|
|
266
|
+
function nearMissOfWidening(nearest: number): boolean {
|
|
267
|
+
return nearest > DEFAULT_KNOWLEDGE_THRESHOLD && nearest <= WIDENED_KNOWLEDGE_THRESHOLD
|
|
268
|
+
}
|
|
269
|
+
|
|
232
270
|
/**
|
|
233
|
-
*
|
|
271
|
+
* Why a near miss may be the embedding model rather than the corpus: the
|
|
272
|
+
* default threshold is tuned for the platform's default embedding model, and
|
|
273
|
+
* another model ranks on-topic passages a little further away. A local
|
|
274
|
+
* runtime widens such a base's threshold when `frontera local dev` applies
|
|
275
|
+
* it, and this says so. Null when the miss is not in that band, or the model
|
|
276
|
+
* is the default or not known.
|
|
277
|
+
*/
|
|
278
|
+
export function embeddingNote(nearest: number, embedding: { provider: string | null; model: string | null } | null, local = true): string | null {
|
|
279
|
+
if (!nearMissOfWidening(nearest)) return null
|
|
280
|
+
if (!embedding?.provider || !embedding.model || sameEmbedding(embedding, PLATFORM_DEFAULT_EMBEDDING)) return null
|
|
281
|
+
// A hosted workspace hears only what it can act on: its own model, and the base's Match threshold.
|
|
282
|
+
if (!local) return `This organization embeds with ${embedding.provider} / ${embedding.model}, not the model the default threshold of ${DEFAULT_KNOWLEDGE_THRESHOLD} is tuned for, so on-topic passages sit further away: if relevant passages are cut off, raise the base's Match threshold.`
|
|
283
|
+
return `This organization embeds with ${embedding.provider} / ${embedding.model}, not the platform's default (${PLATFORM_DEFAULT_EMBEDDING.provider} / ${PLATFORM_DEFAULT_EMBEDDING.model}) the default threshold of ${DEFAULT_KNOWLEDGE_THRESHOLD} is tuned for, so on-topic passages sit further away. A local runtime widens a base's threshold to ${WIDENED_KNOWLEDGE_THRESHOLD} when \`frontera local dev\` applies it, if its file sets none or ${DEFAULT_KNOWLEDGE_THRESHOLD}.`
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Which cutoff the search applied, on the scale `score` is read on: the
|
|
288
|
+
* base's own match threshold unless `--threshold` named one (that is what an
|
|
289
|
+
* Agent's retrieval uses), a maximum cosine distance, so a 0.5 cutoff keeps
|
|
290
|
+
* similarity scores above 0.75 and a 0.70 score is outside it.
|
|
291
|
+
*/
|
|
292
|
+
export function cutoffLine(retrieval: KnowledgeRetrieval | undefined, threshold: number | undefined): string {
|
|
293
|
+
const max = typeof retrieval?.maxDistance === 'number' ? retrieval.maxDistance : threshold
|
|
294
|
+
const from = retrieval?.thresholdFrom === 'request' || (!retrieval && threshold !== undefined) ? '--threshold' : 'the base\'s own match threshold, as an Agent\'s retrieval uses it'
|
|
295
|
+
if (max === undefined) return 'Cutoff: the base\'s own match threshold, as an Agent\'s retrieval uses it (a maximum cosine distance from 0 to 2; lower is stricter).'
|
|
296
|
+
if (retrieval?.scoring === 'fusion' || retrieval?.scoring === 'rerank') {
|
|
297
|
+
return `Cutoff: a maximum cosine distance of ${max}, from ${from}. Scores here are the ${retrieval.scoring === 'rerank' ? 'reranker\'s' : 'keyword and vector fusion\'s'}, so a score isn't comparable to the cutoff.`
|
|
298
|
+
}
|
|
299
|
+
const minScore = typeof retrieval?.minScore === 'number' ? retrieval.minScore : Math.max(0, 1 - max / 2)
|
|
300
|
+
return `Cutoff: a maximum cosine distance of ${max}, from ${from}: scores ≥ ${Number(minScore.toFixed(3))} (score = 1 − distance / 2).`
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Re-run ingestion for a source that failed, or that is stuck pending or
|
|
305
|
+
* processing with no ingestion behind it (`local status` names one).
|
|
234
306
|
*
|
|
235
307
|
* `upload` exits 0 on a partial batch by design — one unreadable file does not
|
|
236
308
|
* end the run — so a failed source is normal and recovery has to be normal
|
|
@@ -246,7 +318,7 @@ const retry: Command = {
|
|
|
246
318
|
{ name: 'source', required: true, description: 'source id, from `frontera knowledge sources`' },
|
|
247
319
|
],
|
|
248
320
|
flags: {},
|
|
249
|
-
summary: 'Re-run ingestion for one source that failed',
|
|
321
|
+
summary: 'Re-run ingestion for one source that failed or is stuck processing',
|
|
250
322
|
examples: ['frontera knowledge retry product-docs <sourceId>'],
|
|
251
323
|
},
|
|
252
324
|
async run(ctx) {
|
|
@@ -511,12 +583,15 @@ const agents: Command = {
|
|
|
511
583
|
rows.length === 0
|
|
512
584
|
? `No agent can read ${ref} — attach one with \`frontera knowledge attach ${ref} <agent>\`.`
|
|
513
585
|
: table(
|
|
514
|
-
['agent', 'id'],
|
|
586
|
+
['agent', 'id', 'attached in'],
|
|
515
587
|
rows.map((r) => {
|
|
516
588
|
const id = String(r.agentId ?? '')
|
|
517
|
-
//
|
|
518
|
-
// so print the id rather than a "?"
|
|
519
|
-
|
|
589
|
+
// The row names the Agent's slug; an older platform's does not, and an agent still in
|
|
590
|
+
// `configuring` is absent from `agent list`, so print the id rather than a "?".
|
|
591
|
+
const slug = typeof r.agentSlug === 'string' && r.agentSlug ? r.agentSlug : slugs.get(id) ?? id
|
|
592
|
+
// Published, staged in its draft, or both; an older platform lists only published ones.
|
|
593
|
+
const where = r.published === false ? 'draft' : r.staged === false ? 'published (its draft drops it)' : r.staged === true ? 'published and draft' : 'published'
|
|
594
|
+
return [slug, id, where]
|
|
520
595
|
}),
|
|
521
596
|
),
|
|
522
597
|
}
|
|
@@ -563,3 +638,30 @@ export const knowledgeCommands: Command[] = [
|
|
|
563
638
|
agents,
|
|
564
639
|
...reserved,
|
|
565
640
|
]
|
|
641
|
+
|
|
642
|
+
/** Whether the command talks to a runtime on this machine (a local runtime is always on a loopback address). */
|
|
643
|
+
/**
|
|
644
|
+
* Whether this runs on the keyless local embeddings: only against the
|
|
645
|
+
* project's own local runtime (`isLocalEmbeddings` reads this computer's
|
|
646
|
+
* keys), read from the organization's embedding setting. False when it
|
|
647
|
+
* can't say, and anywhere else.
|
|
648
|
+
*/
|
|
649
|
+
async function keylessRetrieval(client: PlatformApi, cwd: string, apiUrl: string): Promise<boolean> {
|
|
650
|
+
if (!localRuntimeAt(cwd, apiUrl)) return false
|
|
651
|
+
const embedding = await client.embeddingSetting().catch(() => null)
|
|
652
|
+
return !!embedding && isLocalEmbeddings(embedding)
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/** What `--json` carries beside a base or a search on the keyless local embeddings. */
|
|
656
|
+
export function keylessRetrievalInfo() {
|
|
657
|
+
return { embeddings: 'keyless-local', approximate: true, threshold: KEYLESS_KNOWLEDGE_THRESHOLD, note: KEYLESS_RETRIEVAL_NOTE } as const
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function isLoopbackApi(apiUrl: string): boolean {
|
|
661
|
+
try {
|
|
662
|
+
const host = new URL(apiUrl).hostname
|
|
663
|
+
return host === 'localhost' || host === '127.0.0.1' || host === '[::1]' || host === '::1' || host.endsWith('.localhost')
|
|
664
|
+
} catch {
|
|
665
|
+
return false
|
|
666
|
+
}
|
|
667
|
+
}
|