@bevel-software/platform-core-backend 0.23.0 → 0.25.0
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/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +17 -3
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +3 -0
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +25 -1
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +12 -0
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +10 -0
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core-config.d.ts +16 -0
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +17 -0
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +4 -1
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
- package/dist/modules/access/directory-sync-bot.js +7 -3
- package/dist/modules/access/directory-sync-bot.js.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +8 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.js +8 -2
- package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +38 -6
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +39 -6
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/index.d.ts +2 -1
- package/dist/modules/agent-instructions/index.d.ts.map +1 -1
- package/dist/modules/agent-instructions/index.js +2 -1
- package/dist/modules/agent-instructions/index.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts +115 -0
- package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -0
- package/dist/modules/agent-instructions/shared-file-rules.js +272 -0
- package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -0
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
- package/dist/modules/audit/agent-audit.service.js +4 -2
- package/dist/modules/audit/agent-audit.service.js.map +1 -1
- package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
- package/dist/modules/auth/account-erasure.service.js +57 -16
- package/dist/modules/auth/account-erasure.service.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +25 -15
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.d.ts +20 -2
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +66 -35
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/database/connection.d.ts +16 -0
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +117 -0
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +296 -96
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +81 -31
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/database/migrate.d.ts +95 -1
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +390 -2
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.d.ts +17 -0
- package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.js +29 -0
- package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +8 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +38 -8
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -1
- package/dist/modules/plugins/join-request-records.store.js +7 -4
- package/dist/modules/plugins/join-request-records.store.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +8 -2
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +30 -0
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +42 -31
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/description-length.d.ts +80 -0
- package/dist/modules/tool-registry/description-length.d.ts.map +1 -0
- package/dist/modules/tool-registry/description-length.js +108 -0
- package/dist/modules/tool-registry/description-length.js.map +1 -0
- package/dist/modules/workflow/git/git.service.d.ts +25 -0
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +40 -1
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.service.js +5 -1
- package/dist/modules/workflow/pending-commits.service.js.map +1 -1
- package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
- package/dist/modules/workflow/recovery-bot.js +7 -3
- package/dist/modules/workflow/recovery-bot.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +12 -3
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +4 -1
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/agent-upload.routes.d.ts +77 -0
- package/dist/modules/workspace/agent-upload.routes.d.ts.map +1 -0
- package/dist/modules/workspace/agent-upload.routes.js +210 -0
- package/dist/modules/workspace/agent-upload.routes.js.map +1 -0
- package/dist/modules/workspace/agent-upload.store.d.ts +284 -0
- package/dist/modules/workspace/agent-upload.store.d.ts.map +1 -0
- package/dist/modules/workspace/agent-upload.store.js +553 -0
- package/dist/modules/workspace/agent-upload.store.js.map +1 -0
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +3 -3
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +40 -0
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.js +46 -4
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
- package/dist/modules/workspace/upload-limits.d.ts +13 -0
- package/dist/modules/workspace/upload-limits.d.ts.map +1 -0
- package/dist/modules/workspace/upload-limits.js +13 -0
- package/dist/modules/workspace/upload-limits.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +1 -1
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +13 -0
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +61 -33
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +11 -9
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +570 -134
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +0 -6
- package/dist/modules/workspace/write-denial.d.ts.map +1 -1
- package/dist/modules/workspace/write-denial.js +0 -6
- package/dist/modules/workspace/write-denial.js.map +1 -1
- package/dist/modules/workspace/zip-entry-rules.d.ts +114 -0
- package/dist/modules/workspace/zip-entry-rules.d.ts.map +1 -0
- package/dist/modules/workspace/zip-entry-rules.js +154 -0
- package/dist/modules/workspace/zip-entry-rules.js.map +1 -0
- package/dist/shared/column-crypto.d.ts +194 -0
- package/dist/shared/column-crypto.d.ts.map +1 -0
- package/dist/shared/column-crypto.js +144 -0
- package/dist/shared/column-crypto.js.map +1 -0
- package/dist/shared/token-crypto.d.ts.map +1 -1
- package/dist/shared/token-crypto.js +25 -1
- package/dist/shared/token-crypto.js.map +1 -1
- package/dist/tenancy/static-tenant-source.d.ts.map +1 -1
- package/dist/tenancy/static-tenant-source.js +1 -0
- package/dist/tenancy/static-tenant-source.js.map +1 -1
- package/dist/tenancy/tenant-secrets.d.ts +5 -1
- package/dist/tenancy/tenant-secrets.d.ts.map +1 -1
- package/dist/tenancy/tenant-secrets.js +4 -0
- package/dist/tenancy/tenant-secrets.js.map +1 -1
- package/kb-template/AGENTS.md +42 -0
- package/migrations/0016_pii_encryption.sql +20 -0
- package/migrations/meta/0016_snapshot.json +2327 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +3 -3
- package/src/core/__tests__/lifecycle.test.ts +71 -4
- package/src/core/create-core-server.ts +21 -3
- package/src/core/create-core-services.ts +27 -1
- package/src/core/lifecycle.ts +19 -0
- package/src/core-config.ts +18 -0
- package/src/index.ts +25 -0
- package/src/modules/access/__tests__/users-db-double.ts +21 -12
- package/src/modules/access/access.routes.ts +4 -1
- package/src/modules/access/directory-sync-bot.ts +7 -3
- package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +8 -4
- package/src/modules/agent-instructions/__tests__/compose.test.ts +19 -10
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +238 -0
- package/src/modules/agent-instructions/agent-instructions.routes.ts +12 -2
- package/src/modules/agent-instructions/compose.ts +50 -7
- package/src/modules/agent-instructions/index.ts +12 -0
- package/src/modules/agent-instructions/shared-file-rules.ts +314 -0
- package/src/modules/audit/agent-audit.service.ts +4 -2
- package/src/modules/auth/__tests__/account-deactivation.test.ts +2 -1
- package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +6 -2
- package/src/modules/auth/__tests__/account.routes.test.ts +6 -3
- package/src/modules/auth/__tests__/auth.service.test.ts +3 -1
- package/src/modules/auth/account-erasure.service.ts +69 -18
- package/src/modules/auth/auth.service.ts +33 -23
- package/src/modules/code-mode/__tests__/chain-runtime.e2e.test.ts +335 -0
- package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +46 -2
- package/src/modules/code-mode/code-mode.tool.ts +80 -34
- package/src/modules/database/__tests__/connection.test.ts +12 -0
- package/src/modules/database/__tests__/pii-backfill.pg.test.ts +780 -0
- package/src/modules/database/connection.ts +117 -0
- package/src/modules/database/core-schema.ts +81 -31
- package/src/modules/database/migrate.ts +540 -2
- package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +93 -0
- package/src/modules/kb-fs/locking-filesystem.ts +37 -0
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +4 -3
- package/src/modules/mcp/__tests__/mcp.service.test.ts +47 -7
- package/src/modules/mcp/mcp.service.ts +46 -7
- package/src/modules/plugins/join-request-records.store.ts +7 -4
- package/src/modules/tool-auth/external-api-key.service.ts +8 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +151 -0
- package/src/modules/tool-manuals/tool-manuals.service.ts +37 -0
- package/src/modules/tool-manuals/tool-manuals.tools.ts +44 -31
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +378 -0
- package/src/modules/tool-registry/description-length.ts +111 -0
- package/src/modules/workflow/git/__tests__/git.service.prFetchFailure.test.ts +170 -0
- package/src/modules/workflow/git/git.service.ts +47 -1
- package/src/modules/workflow/pending-commits.service.ts +5 -1
- package/src/modules/workflow/recovery-bot.ts +7 -3
- package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +4 -0
- package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +25 -3
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +12 -3
- package/src/modules/workflow/workflow.service.ts +4 -1
- package/src/modules/workspace/__tests__/agent-uploads.test.ts +1604 -0
- package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +24 -14
- package/src/modules/workspace/__tests__/workspace.service.any-workspace-credentials.test.ts +156 -0
- package/src/modules/workspace/__tests__/workspace.service.replaced-repository.test.ts +77 -1
- package/src/modules/workspace/__tests__/workspace.service.test.ts +57 -0
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +39 -36
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +196 -46
- package/src/modules/workspace/agent-upload.routes.ts +214 -0
- package/src/modules/workspace/agent-upload.store.ts +668 -0
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +9 -9
- package/src/modules/workspace/startup/steps/seed-tree.ts +3 -6
- package/src/modules/workspace/startup/steps/template-source.ts +53 -5
- package/src/modules/workspace/upload-limits.ts +12 -0
- package/src/modules/workspace/workspace.routes.ts +1 -2
- package/src/modules/workspace/workspace.service.ts +63 -37
- package/src/modules/workspace/workspace.tools.ts +647 -148
- package/src/modules/workspace/write-denial.ts +0 -8
- package/src/modules/workspace/zip-entry-rules.ts +173 -0
- package/src/shared/__tests__/column-crypto.test.ts +217 -0
- package/src/shared/column-crypto.ts +218 -0
- package/src/shared/token-crypto.ts +28 -1
- package/src/tenancy/__tests__/static-tenant-source.test.ts +4 -0
- package/src/tenancy/static-tenant-source.ts +1 -0
- package/src/tenancy/tenant-secrets.ts +5 -1
|
@@ -2,20 +2,53 @@ import '@utcp/direct-call';
|
|
|
2
2
|
import { createTool } from '@mastra/core/tools';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { CodeModeUtcpClient } from '@utcp/code-mode';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
omitImagePayloads,
|
|
7
|
+
retiredToolInFailure,
|
|
8
|
+
CHAIN_TIMEOUT_DEFAULT_MS,
|
|
9
|
+
CHAIN_TIMEOUT_MAX_MS,
|
|
10
|
+
CHAIN_TIMEOUT_MIN_MS,
|
|
11
|
+
chainExample,
|
|
12
|
+
type ChainExampleTool,
|
|
13
|
+
runToolChain,
|
|
14
|
+
} from '@bevel-software/platform-mcp-core';
|
|
6
15
|
import type { SpillStore } from '../workspace/spill-store.js';
|
|
7
16
|
import { utcpNameToTsInterfaceName, findToolByName, AmbiguousToolNameError } from './code-mode-names.js';
|
|
8
17
|
|
|
18
|
+
/**
|
|
19
|
+
* The in-process agent's three code-mode tools.
|
|
20
|
+
*
|
|
21
|
+
* `namespace` is the UTCP manual the knowledge-base tools are registered under
|
|
22
|
+
* for THIS client, and every example in the descriptions is written against it.
|
|
23
|
+
* It is a parameter rather than fixed text because it is not the same name on
|
|
24
|
+
* every surface — the hosted endpoint registers `KNOWLEDGE_BASE`, the local MCP
|
|
25
|
+
* server registers the whole deployment as `hexis` — and a description naming
|
|
26
|
+
* the other one taught the agent a namespace the runtime had no binding for.
|
|
27
|
+
*
|
|
28
|
+
* `tools` is this client's catalog — names AND input schemas — and is used only
|
|
29
|
+
* to write an EXAMPLE call that actually runs. Both halves are needed: the
|
|
30
|
+
* namespace does not say how deeply a tool's name is nested, and the name does
|
|
31
|
+
* not say which of its arguments are required (see `chainExample`). Passing
|
|
32
|
+
* nothing prints no concrete example, which is the honest default for a caller
|
|
33
|
+
* that has not handed over its catalog.
|
|
34
|
+
*/
|
|
9
35
|
export function createCallToolChainTool(
|
|
10
36
|
client: CodeModeUtcpClient,
|
|
11
37
|
spillStore: SpillStore,
|
|
38
|
+
namespace: string,
|
|
39
|
+
tools: readonly ChainExampleTool[] = [],
|
|
12
40
|
) {
|
|
41
|
+
const { namespace: ns, call } = chainExample(namespace, tools);
|
|
42
|
+
// Printed only when the catalog determines every required argument, so a
|
|
43
|
+
// copied example never 400s on a missing one; see `chainExample`.
|
|
44
|
+
const worked = call ? ` A call that works exactly as written: \`return ${call};\`.` : '';
|
|
13
45
|
return createTool({
|
|
14
46
|
id: 'call_tool_chain',
|
|
15
47
|
description: [
|
|
16
48
|
CodeModeUtcpClient.AGENT_PROMPT_TEMPLATE,
|
|
17
|
-
|
|
49
|
+
`Execute JavaScript code with direct access to all registered UTCP tools as hierarchical functions — call them as \`${ns}.<tool>({ body: { ...args } })\`, synchronous, no await.${worked} Every argument a tool declares REQUIRED must be present — for the knowledge-base tools that includes \`branch\`. The runtime is plain JavaScript — no type annotations or other TypeScript-only syntax — plus \`atob\`, \`btoa\`, \`TextEncoder\` and \`TextDecoder\` for base64 and UTF-8 bytes, as in a browser; there is no \`Buffer\`, no \`fetch\` and no \`require\`. Return the final value with \`return\`. Use \`list_tools\` and \`tools_info\` first to discover available tools and their interfaces.`,
|
|
18
50
|
'Error handling inside the chain: a failing tool call THROWS, and the thrown error\'s `.message` holds the server\'s actual reason (e.g. a 403 with the explanation, not just a status code). If you catch it, surface `err.message` (and `err.status` / `err.data` when present) — NEVER `return { error: err }` or otherwise return the raw Error object, because an Error serializes to `{}` (its `message` is non-enumerable) and the reason is lost. If you don\'t need to handle it, just let it throw — the runtime already reports `err.message` back to you.',
|
|
51
|
+
`Failures are answered, never dropped: a chain that throws comes back with \`success: false\` and the reason, and one that outlives \`timeout\` (default ${CHAIN_TIMEOUT_DEFAULT_MS} ms, maximum ${CHAIN_TIMEOUT_MAX_MS} ms) comes back saying it timed out — raise \`timeout\` or split the work and run it again. Either way your next tool call works as usual.`,
|
|
19
52
|
'Large return values: if the returned value exceeds `max_output_size`, the full JSON is auto-spilled to a shared spill store (outside any workspace, never committed) and the response contains only a `__tool_chain_spill__/…` ref + a truncated marker. You can read the spill back with the regular `read_file` tool — pass that ref as `path` (its `branch` is ignored) plus `offset` / `limit` to slice it, never read a multi-MB file in full. Order of preference: (1) re-run `call_tool_chain` with a follow-up code chain that filters/maps the data inline and returns just what you need; (2) narrow the API call — shorter `fields`, tighter date window, lower `limit`; (3) last resort — `read_file` against the spill ref with `offset` / `limit`. The spill is read-only context only; do NOT use it as a way to persist KB content — for KB writes use the regular `write_file` / `edit_file` tools, which go through the lock/commit pipeline.',
|
|
20
53
|
].join('\n\n'),
|
|
21
54
|
inputSchema: z.object({
|
|
@@ -26,11 +59,11 @@ export function createCallToolChainTool(
|
|
|
26
59
|
timeout: z
|
|
27
60
|
.number()
|
|
28
61
|
.int()
|
|
29
|
-
.min(
|
|
30
|
-
.max(
|
|
62
|
+
.min(CHAIN_TIMEOUT_MIN_MS)
|
|
63
|
+
.max(CHAIN_TIMEOUT_MAX_MS)
|
|
31
64
|
.optional()
|
|
32
|
-
.default(
|
|
33
|
-
.describe(
|
|
65
|
+
.default(CHAIN_TIMEOUT_DEFAULT_MS)
|
|
66
|
+
.describe(`Timeout in milliseconds (default: ${CHAIN_TIMEOUT_DEFAULT_MS}, max: ${CHAIN_TIMEOUT_MAX_MS}).`),
|
|
34
67
|
max_output_size: z
|
|
35
68
|
.number()
|
|
36
69
|
.int()
|
|
@@ -41,15 +74,35 @@ export function createCallToolChainTool(
|
|
|
41
74
|
.describe('Max size of the stringified result in characters (default: 200000, max: 1000000). If exceeded, the full result is spilled to the shared spill store and only a `__tool_chain_spill__/…` ref is returned.'),
|
|
42
75
|
}),
|
|
43
76
|
execute: async (input) => {
|
|
44
|
-
const timeout = input.timeout ??
|
|
77
|
+
const timeout = input.timeout ?? CHAIN_TIMEOUT_DEFAULT_MS;
|
|
45
78
|
const maxOutputSize = input.max_output_size ?? 200_000;
|
|
79
|
+
// The shared runner always answers: the chain's browser globals are in
|
|
80
|
+
// place, and a timeout, an exhausted heap and an unknown namespace each
|
|
81
|
+
// come back as the sentence that says so rather than as a success with a
|
|
82
|
+
// null result (which is what the runner's own resolved shape looks like).
|
|
83
|
+
const outcome = await runToolChain(client, input.code, timeout);
|
|
84
|
+
if (!outcome.ok) {
|
|
85
|
+
// A chain that failed while calling a REMOVED tool gets the reason it
|
|
86
|
+
// was removed (who does it now, and where), not "is not a function".
|
|
87
|
+
// The failure is the signal, not the chain's source: a chain that only
|
|
88
|
+
// mentions the name and died of something else keeps its own error.
|
|
89
|
+
const message = retiredToolInFailure(outcome.error) ?? outcome.error;
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: message,
|
|
93
|
+
...(outcome.logs.length ? { logs: outcome.logs } : {}),
|
|
94
|
+
...(outcome.status !== undefined ? { status: outcome.status } : {}),
|
|
95
|
+
...(outcome.data !== undefined ? { data: outcome.data } : {}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const { result: rawResult, logs } = outcome;
|
|
99
|
+
// Everything past the outcome is still fallible — `omitImagePayloads`
|
|
100
|
+
// walks a value the chain built, `JSON.stringify` can meet a cycle or a
|
|
101
|
+
// BigInt, and the spill store writes to disk. This tool promises a
|
|
102
|
+
// STRUCTURED failure for every outcome, so a disk or serialization error
|
|
103
|
+
// must come back as `success: false` with its reason rather than as an
|
|
104
|
+
// unhandled tool failure the agent sees as a dropped call.
|
|
46
105
|
try {
|
|
47
|
-
const { result: rawResult, logs } = await client.callToolChain(input.code, timeout);
|
|
48
|
-
// The runner reports a failed chain in `logs` rather than throwing, so
|
|
49
|
-
// a chain that died calling a removed tool is recognised here: the agent
|
|
50
|
-
// gets who does it now, not "is not a function".
|
|
51
|
-
const retired = retiredToolChainFailure({ result: rawResult, logs });
|
|
52
|
-
if (retired) return { success: false, error: retired, logs };
|
|
53
106
|
// Same policy as the MCP surfaces' `call_tool_chain` (see
|
|
54
107
|
// `omitImagePayloads`): a chain result is stringified JSON, so an image
|
|
55
108
|
// read inside it comes back as an omitted-image note instead of a
|
|
@@ -68,36 +121,30 @@ export function createCallToolChainTool(
|
|
|
68
121
|
result_bytes: bytes,
|
|
69
122
|
message: `Combined result+logs payload was ${fullJson.length} characters (exceeded max_output_size of ${maxOutputSize}). Full JSON (both \`result\` and \`logs\`) saved to the shared spill store as \`${ref}\` (outside any workspace, uncommitted). Read it back with \`read_file\` — pass that ref as \`path\` (\`branch\` is ignored) plus \`offset\` / \`limit\` for a slice — or, usually better, narrow the next \`call_tool_chain\` call (smaller fields list, tighter date window, lower limit) so the result fits inline.`,
|
|
70
123
|
};
|
|
71
|
-
} catch (
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
// them through to the agent — `e.message` already holds the server's
|
|
76
|
-
// reason, and `status` / `data` give it the structured detail.
|
|
77
|
-
const raw = e instanceof Error ? e.message : String(e);
|
|
78
|
-
// A chain that failed while calling a removed tool gets the reason it
|
|
79
|
-
// was removed (who does it now, and where), not "is not a function".
|
|
80
|
-
// The thrown failure is the signal, not the chain's source: a chain
|
|
81
|
-
// that only mentions the name and died of something else keeps its own
|
|
82
|
-
// error, instead of hiding it behind a migration notice.
|
|
83
|
-
const message = retiredToolInFailure(raw) ?? raw;
|
|
84
|
-
const status = (e as { status?: unknown })?.status;
|
|
85
|
-
const data = (e as { data?: unknown })?.data;
|
|
124
|
+
} catch (err) {
|
|
125
|
+
// The chain itself SUCCEEDED and only its delivery failed, so the logs
|
|
126
|
+
// ride along: they are the only trace of the work left, and an agent
|
|
127
|
+
// deciding whether to re-run a long chain needs them.
|
|
86
128
|
return {
|
|
87
129
|
success: false,
|
|
88
|
-
error: message
|
|
89
|
-
...(
|
|
90
|
-
...(data !== undefined ? { data } : {}),
|
|
130
|
+
error: `The chain ran, but its result could not be returned: ${err instanceof Error ? err.message : String(err)}. Re-run a narrower chain that returns only what you need.`,
|
|
131
|
+
...(logs.length ? { logs } : {}),
|
|
91
132
|
};
|
|
92
133
|
}
|
|
93
134
|
},
|
|
94
135
|
});
|
|
95
136
|
}
|
|
96
137
|
|
|
97
|
-
export function createListToolsTool(
|
|
138
|
+
export function createListToolsTool(
|
|
139
|
+
client: CodeModeUtcpClient,
|
|
140
|
+
namespace: string,
|
|
141
|
+
tools: readonly ChainExampleTool[] = [],
|
|
142
|
+
) {
|
|
143
|
+
const { name } = chainExample(namespace, tools);
|
|
98
144
|
return createTool({
|
|
99
145
|
id: 'list_tools',
|
|
100
|
-
|
|
146
|
+
// A name the catalog really has, or none: see `ChainExample.name`.
|
|
147
|
+
description: `Returns a list of all UTCP tool names currently registered, in their TypeScript-accessible form${name ? ` (e.g. \`${name}\`)` : ''}.`,
|
|
101
148
|
inputSchema: z.object({}),
|
|
102
149
|
execute: async () => {
|
|
103
150
|
const tools = await client.config.tool_repository.getTools();
|
|
@@ -105,7 +152,6 @@ export function createListToolsTool(client: CodeModeUtcpClient) {
|
|
|
105
152
|
},
|
|
106
153
|
});
|
|
107
154
|
}
|
|
108
|
-
|
|
109
155
|
export function createToolsInfoTool(client: CodeModeUtcpClient) {
|
|
110
156
|
return createTool({
|
|
111
157
|
id: 'tools_info',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
1
2
|
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
3
|
import {
|
|
3
4
|
DEFAULT_DB_SCHEMA,
|
|
@@ -88,6 +89,17 @@ describe('getDb', () => {
|
|
|
88
89
|
expect(getDb(URL, { schema: DEFAULT_DB_SCHEMA })).toBe(plain);
|
|
89
90
|
});
|
|
90
91
|
|
|
92
|
+
it('hands the cached pool to a caller holding the same key spelled otherwise, and refuses another key', () => {
|
|
93
|
+
const raw = randomBytes(32);
|
|
94
|
+
const first = getDb(URL, { schema: 'keyed', piiKey: raw.toString('base64') });
|
|
95
|
+
opened.push(first);
|
|
96
|
+
// The same 32 bytes as hex: one key, so one pool.
|
|
97
|
+
expect(getDb(URL, { schema: 'keyed', piiKey: raw.toString('hex') })).toBe(first);
|
|
98
|
+
expect(() => getDb(URL, { schema: 'keyed', piiKey: randomBytes(32).toString('base64') })).toThrow(
|
|
99
|
+
/already open with a different personal-data key/,
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
91
103
|
it('opens a fresh pool after the cached one was closed', async () => {
|
|
92
104
|
const first = getDb(URL, { schema: 'closing' });
|
|
93
105
|
await closeDb(first);
|