@arnilo/prism-tools 0.0.0-stage → 0.13.1
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/CHANGELOG.md +418 -0
- package/LICENSE +21 -0
- package/README.md +44 -2
- package/browser/README.md +98 -0
- package/browser/skills/browser-automation/SKILL.md +14 -0
- package/browser/src/actions/cdp.ts +131 -0
- package/browser/src/actions/dialog.ts +25 -0
- package/browser/src/actions/download_release.ts +22 -0
- package/browser/src/actions/index.ts +37 -0
- package/browser/src/actions/locator.ts +70 -0
- package/browser/src/actions/navigate.ts +23 -0
- package/browser/src/actions/screenshot.ts +27 -0
- package/browser/src/actions/scroll.ts +24 -0
- package/browser/src/actions/select_page.ts +21 -0
- package/browser/src/actions/types.ts +114 -0
- package/browser/src/actions/upload.ts +44 -0
- package/browser/src/actions/wait.ts +45 -0
- package/browser/src/browser.ts +197 -0
- package/browser/src/cdp.ts +178 -0
- package/browser/src/checkpoint.ts +189 -0
- package/browser/src/config.ts +72 -0
- package/browser/src/downloads.ts +253 -0
- package/browser/src/errors.ts +31 -0
- package/browser/src/evaluate.ts +101 -0
- package/browser/src/index.ts +129 -0
- package/browser/src/limits.ts +271 -0
- package/browser/src/manager.ts +730 -0
- package/browser/src/network.ts +263 -0
- package/browser/src/observe.ts +178 -0
- package/browser/src/policy.ts +133 -0
- package/browser/src/screenshot.ts +107 -0
- package/browser/src/shared-sandbox.ts +53 -0
- package/browser/src/snapshot.ts +99 -0
- package/browser/src/targets.ts +165 -0
- package/browser/src/tools.ts +480 -0
- package/browser/src/types.ts +316 -0
- package/browser/src/uploads.ts +174 -0
- package/coding/README.md +337 -0
- package/coding/src/agent/acp-operations.ts +146 -0
- package/coding/src/agent/artifacts.ts +38 -0
- package/coding/src/agent/ask-user-decision.ts +623 -0
- package/coding/src/agent/atomic-write.ts +23 -0
- package/coding/src/agent/bounded-file.ts +21 -0
- package/coding/src/agent/checks.ts +301 -0
- package/coding/src/agent/coding-checkpoint.ts +828 -0
- package/coding/src/agent/delete.ts +237 -0
- package/coding/src/agent/diagnostics-tool.ts +163 -0
- package/coding/src/agent/diagnostics.ts +262 -0
- package/coding/src/agent/edit-diff.ts +382 -0
- package/coding/src/agent/edit.ts +322 -0
- package/coding/src/agent/effects.ts +102 -0
- package/coding/src/agent/env.ts +28 -0
- package/coding/src/agent/execution-policy.ts +89 -0
- package/coding/src/agent/file-mutation-queue.ts +72 -0
- package/coding/src/agent/forge/github.ts +603 -0
- package/coding/src/agent/forge/index.ts +16 -0
- package/coding/src/agent/forge/types.ts +185 -0
- package/coding/src/agent/git-aware-repository.ts +305 -0
- package/coding/src/agent/git-exec.ts +326 -0
- package/coding/src/agent/git-status.ts +177 -0
- package/coding/src/agent/git-tools.ts +360 -0
- package/coding/src/agent/git.ts +1074 -0
- package/coding/src/agent/glob-match.ts +146 -0
- package/coding/src/agent/glob.ts +182 -0
- package/coding/src/agent/goal-verify.ts +385 -0
- package/coding/src/agent/grep-worker.ts +74 -0
- package/coding/src/agent/grep.ts +459 -0
- package/coding/src/agent/identity.ts +48 -0
- package/coding/src/agent/index.ts +676 -0
- package/coding/src/agent/language/client.ts +429 -0
- package/coding/src/agent/language/framing.ts +190 -0
- package/coding/src/agent/language/index.ts +23 -0
- package/coding/src/agent/language/intelligence.ts +682 -0
- package/coding/src/agent/language/types.ts +187 -0
- package/coding/src/agent/lifecycle-events.ts +121 -0
- package/coding/src/agent/lifecycle.ts +166 -0
- package/coding/src/agent/limits.ts +214 -0
- package/coding/src/agent/move.ts +178 -0
- package/coding/src/agent/mutation-path.ts +52 -0
- package/coding/src/agent/output-accumulator.ts +304 -0
- package/coding/src/agent/path-utils.ts +120 -0
- package/coding/src/agent/process/index.ts +58 -0
- package/coding/src/agent/process/recovery.ts +508 -0
- package/coding/src/agent/process/sessions-host.ts +222 -0
- package/coding/src/agent/process/sessions-monitor.ts +141 -0
- package/coding/src/agent/process/sessions-recovery.ts +241 -0
- package/coding/src/agent/process/sessions-spawn.ts +613 -0
- package/coding/src/agent/process/sessions-teardown.ts +281 -0
- package/coding/src/agent/process/sessions.ts +30 -0
- package/coding/src/agent/process/types.ts +358 -0
- package/coding/src/agent/read-path-set.ts +126 -0
- package/coding/src/agent/read.ts +713 -0
- package/coding/src/agent/repository/glob.ts +147 -0
- package/coding/src/agent/repository/indexed-search.ts +480 -0
- package/coding/src/agent/repository/list.ts +131 -0
- package/coding/src/agent/repository/operations.ts +22 -0
- package/coding/src/agent/repository/path.ts +98 -0
- package/coding/src/agent/repository/search.ts +277 -0
- package/coding/src/agent/repository/types.ts +243 -0
- package/coding/src/agent/repository/walk.ts +126 -0
- package/coding/src/agent/repository.ts +12 -0
- package/coding/src/agent/shell-background.ts +264 -0
- package/coding/src/agent/shell-output.ts +75 -0
- package/coding/src/agent/shell.ts +526 -0
- package/coding/src/agent/todo.ts +399 -0
- package/coding/src/agent/truncate.ts +251 -0
- package/coding/src/agent/write.ts +170 -0
- package/coding/src/ask-user-host.ts +48 -0
- package/coding/src/config.ts +278 -0
- package/coding/src/hard-deny.ts +97 -0
- package/coding/src/index.ts +318 -0
- package/coding/src/principal-guard.ts +84 -0
- package/coding/src/sandbox.ts +92 -0
- package/coding/src/security/approval.ts +144 -0
- package/coding/src/security/command-rules.ts +57 -0
- package/coding/src/security/docker-cli.ts +222 -0
- package/coding/src/security/docker-sandbox.ts +1205 -0
- package/coding/src/security/e2b-sandbox.ts +853 -0
- package/coding/src/security/egress/dns-pin.ts +88 -0
- package/coding/src/security/egress/index.ts +32 -0
- package/coding/src/security/egress/limits.ts +57 -0
- package/coding/src/security/egress/policy.ts +137 -0
- package/coding/src/security/egress/proxy.ts +599 -0
- package/coding/src/security/egress/types.ts +30 -0
- package/coding/src/security/index.ts +199 -0
- package/coding/src/security/native-sandbox.ts +639 -0
- package/coding/src/security/path-containment.ts +55 -0
- package/coding/src/security/sandbox-coding-operations.ts +392 -0
- package/coding/src/security/sandbox-fs-operations.ts +644 -0
- package/coding/src/security/sandbox-limits.ts +147 -0
- package/coding/src/security/sandbox-tar.ts +308 -0
- package/coding/src/security/sandbox.ts +179 -0
- package/coding/src/security/semaphore.ts +55 -0
- package/coding/src/targets.ts +110 -0
- package/coding/src/workspace/diff.ts +78 -0
- package/coding/src/workspace/errors.ts +29 -0
- package/coding/src/workspace/index.ts +5 -0
- package/coding/src/workspace/merge.ts +151 -0
- package/coding/src/workspace/routing.ts +76 -0
- package/coding/src/workspace/service.ts +584 -0
- package/computer-use/README.md +105 -0
- package/computer-use/skills/computer-use-linux/SKILL.md +17 -0
- package/computer-use/src/classify.ts +53 -0
- package/computer-use/src/command.ts +29 -0
- package/computer-use/src/config.ts +69 -0
- package/computer-use/src/create.ts +170 -0
- package/computer-use/src/devices.ts +247 -0
- package/computer-use/src/env.ts +28 -0
- package/computer-use/src/index.ts +157 -0
- package/computer-use/src/skill.ts +21 -0
- package/openapi/README.md +97 -0
- package/openapi/src/compile.ts +386 -0
- package/openapi/src/config.ts +73 -0
- package/openapi/src/errors.ts +16 -0
- package/openapi/src/execute.ts +241 -0
- package/openapi/src/index.ts +124 -0
- package/openapi/src/limits.ts +63 -0
- package/openapi/src/specs.ts +86 -0
- package/openapi/src/tools.ts +60 -0
- package/openapi/src/types.ts +61 -0
- package/package.json +171 -4
- package/research/README.md +72 -0
- package/research/skills/research-report/SKILL.md +12 -0
- package/research/skills/research-scoping/SKILL.md +10 -0
- package/research/skills/research-synthesis/SKILL.md +10 -0
- package/research/skills/source-triage/SKILL.md +10 -0
- package/research/src/check.ts +71 -0
- package/research/src/config.ts +41 -0
- package/research/src/index.ts +147 -0
- package/research/src/ledger.ts +157 -0
- package/research/src/urls.ts +21 -0
- package/web/README.md +287 -0
- package/web/skills/web-research/SKILL.md +17 -0
- package/web/src/brave.ts +66 -0
- package/web/src/cache.ts +151 -0
- package/web/src/config.ts +210 -0
- package/web/src/controls.ts +128 -0
- package/web/src/domains.ts +114 -0
- package/web/src/exa.ts +60 -0
- package/web/src/firecrawl.ts +160 -0
- package/web/src/index.ts +387 -0
- package/web/src/kagi.ts +73 -0
- package/web/src/limits.ts +55 -0
- package/web/src/native/convert.ts +84 -0
- package/web/src/native/fetch.ts +226 -0
- package/web/src/normalize.ts +131 -0
- package/web/src/obscura/cdp.ts +201 -0
- package/web/src/obscura/classify.ts +35 -0
- package/web/src/obscura/cli.ts +254 -0
- package/web/src/obscura/errors.ts +8 -0
- package/web/src/obscura/index.ts +59 -0
- package/web/src/obscura/limits.ts +92 -0
- package/web/src/obscura/mcp.ts +104 -0
- package/web/src/obscura/playwright.ts +133 -0
- package/web/src/obscura/process.ts +235 -0
- package/web/src/obscura/search-profile.ts +73 -0
- package/web/src/obscura/types.ts +48 -0
- package/web/src/obscura/web.ts +419 -0
- package/web/src/prompt-fetch.ts +88 -0
- package/web/src/render.ts +75 -0
- package/web/src/searxng.ts +78 -0
- package/web/src/slice.ts +139 -0
- package/web/src/tavily.ts +77 -0
- package/web/src/tools.ts +182 -0
- package/web/src/transport.ts +310 -0
- package/web/src/types.ts +199 -0
- package/work/README.md +77 -0
- package/work/THIRD_PARTY_NOTICES +24 -0
- package/work/docling/ocr.py +150 -0
- package/work/sandbox/Dockerfile +36 -0
- package/work/sandbox/soffice.sh +12 -0
- package/work/src/command.ts +29 -0
- package/work/src/config.ts +138 -0
- package/work/src/connectors/cli.ts +343 -0
- package/work/src/connectors/drafts.ts +647 -0
- package/work/src/connectors/errors.ts +8 -0
- package/work/src/connectors/file-bytes.ts +149 -0
- package/work/src/connectors/google-workspace-http.ts +399 -0
- package/work/src/connectors/google-workspace.ts +465 -0
- package/work/src/connectors/gws-tools.ts +378 -0
- package/work/src/connectors/http.ts +123 -0
- package/work/src/connectors/idempotency.ts +235 -0
- package/work/src/connectors/identity.ts +34 -0
- package/work/src/connectors/index.ts +93 -0
- package/work/src/connectors/limits.ts +50 -0
- package/work/src/connectors/m365-tools.ts +308 -0
- package/work/src/connectors/microsoft365-http.ts +428 -0
- package/work/src/connectors/microsoft365.ts +402 -0
- package/work/src/connectors/normalize.ts +120 -0
- package/work/src/connectors/tool-helpers.ts +398 -0
- package/work/src/connectors/tools.ts +42 -0
- package/work/src/connectors/types.ts +399 -0
- package/work/src/diagrams/canonicalize.ts +166 -0
- package/work/src/diagrams/caps.ts +52 -0
- package/work/src/diagrams/embed.ts +340 -0
- package/work/src/diagrams/errors.ts +76 -0
- package/work/src/diagrams/index.ts +81 -0
- package/work/src/diagrams/messages.ts +150 -0
- package/work/src/diagrams/origin.ts +52 -0
- package/work/src/diagrams/telemetry.ts +34 -0
- package/work/src/diagrams/xml.ts +267 -0
- package/work/src/document-extraction/index.ts +563 -0
- package/work/src/document-reader/ambient.d.ts +2 -0
- package/work/src/document-reader/errors.ts +7 -0
- package/work/src/document-reader/index.ts +181 -0
- package/work/src/document-reader/mistral-ocr.ts +318 -0
- package/work/src/document-reader/parsers.ts +171 -0
- package/work/src/documents/caps.ts +135 -0
- package/work/src/documents/diff.ts +269 -0
- package/work/src/documents/errors.ts +44 -0
- package/work/src/documents/fidelity.ts +98 -0
- package/work/src/documents/generate.ts +96 -0
- package/work/src/documents/hash.ts +8 -0
- package/work/src/documents/index.ts +14 -0
- package/work/src/documents/model-schema.ts +639 -0
- package/work/src/documents/parse.ts +252 -0
- package/work/src/documents/patch-history.ts +81 -0
- package/work/src/documents/patch.ts +476 -0
- package/work/src/documents/preview-html.ts +245 -0
- package/work/src/documents/preview.ts +227 -0
- package/work/src/documents/telemetry.ts +36 -0
- package/work/src/documents/translate/docx.ts +292 -0
- package/work/src/documents/translate/pptx.ts +304 -0
- package/work/src/documents/translate/xlsx.ts +137 -0
- package/work/src/documents/types.ts +188 -0
- package/work/src/index.ts +311 -0
- package/work/src/runtime/worker-pool-entry.ts +102 -0
- package/work/src/runtime/worker-pool.ts +267 -0
- package/work/src/sandbox/composition.ts +212 -0
- package/work/src/sandbox/image.ts +6 -0
- package/work/src/sandbox/index.ts +14 -0
- package/work/src/sheets/caps.ts +68 -0
- package/work/src/sheets/csv.ts +351 -0
- package/work/src/sheets/decimal.ts +388 -0
- package/work/src/sheets/errors.ts +52 -0
- package/work/src/sheets/index.ts +62 -0
- package/work/src/sheets/inference.ts +378 -0
- package/work/src/sheets/telemetry.ts +34 -0
- package/work/src/sheets/types.ts +162 -0
- package/work/src/sheets/xlsx.ts +388 -0
- package/work/src/skills/index.ts +8 -0
- package/work/src/skills/load.ts +43 -0
- package/work/src/tools/filesystem.ts +21 -0
- package/work/src/tools/index.ts +1 -0
- package/work/src/tools/local-filesystem.ts +33 -0
- package/work/src/tools/office.ts +311 -0
- package/work/vendor/hermes-agent/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/SKILL.md +196 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_comments.py +289 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_common.py +94 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_create.py +177 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_edit.py +250 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_read.py +149 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_revisions.py +147 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_template.py +70 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_validate.py +156 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/SKILL.md +125 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/_raster.py +76 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_marker.py +88 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_pymupdf.py +101 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_create.py +130 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_fill_form.py +97 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_form_layout.py +168 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_make_form.py +145 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_merge.py +50 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_meta.py +115 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_page_image.py +99 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_read.py +153 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_secure.py +71 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_split.py +84 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_stamp.py +143 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_watermark.py +51 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/SKILL.md +220 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_create.py +214 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_edit.py +436 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_from_template.py +88 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_read.py +131 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_render.py +93 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/SKILL.md +196 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/csv_to_xlsx.py +104 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_create.py +259 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_edit.py +263 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_read.py +160 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_recalc.py +111 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_restructure.py +337 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_to_csv.py +69 -0
- package/work/vendor-lock.json +11 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { type JsonObject, type ToolDefinition, type ToolExecutionContext, type ToolResult, UNTRUSTED_EXTERNAL_TRUST } from "@arnilo/prism";
|
|
2
|
+
import { type ArtifactBodyRef } from "@arnilo/prism/artifacts";
|
|
3
|
+
import { resolveSandboxPath } from "../tools/filesystem.js";
|
|
4
|
+
import { computePayloadDigest, extractDraftRecipients, validateApproval } from "./drafts.js";
|
|
5
|
+
import { WorkToolError } from "./errors.js";
|
|
6
|
+
import { artifactRef, readUploadBytes, sha256 } from "./file-bytes.js";
|
|
7
|
+
import { identityKey } from "./idempotency.js";
|
|
8
|
+
import { assertIdentityActive } from "./identity.js";
|
|
9
|
+
import { resolveWorkLimits } from "./limits.js";
|
|
10
|
+
import type {
|
|
11
|
+
GoogleWorkspaceAdapter,
|
|
12
|
+
Microsoft365Adapter,
|
|
13
|
+
WorkApprovalCheckInput,
|
|
14
|
+
WorkDraft,
|
|
15
|
+
WorkDraftApproval,
|
|
16
|
+
WorkMutationRecord,
|
|
17
|
+
WorkProvider,
|
|
18
|
+
WorkToolsOptions,
|
|
19
|
+
} from "./types.js";
|
|
20
|
+
export function objectSchema(properties: JsonObject, required: readonly string[]): JsonObject {
|
|
21
|
+
return { type: "object", properties, required: [...required], additionalProperties: false };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function reqString(args: JsonObject, key: string): string {
|
|
25
|
+
const value = args[key];
|
|
26
|
+
if (typeof value !== "string" || !value) throw new WorkToolError("ERR_PRISM_WORK_INPUT", `${key} must be a non-empty string`);
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function optString(args: JsonObject, key: string): string | undefined {
|
|
31
|
+
const value = args[key];
|
|
32
|
+
if (value === undefined) return undefined;
|
|
33
|
+
if (typeof value !== "string") throw new WorkToolError("ERR_PRISM_WORK_INPUT", `${key} must be a string`);
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const ARTIFACT: JsonObject = {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
tenantId: { type: "string" },
|
|
41
|
+
accountId: { type: "string" },
|
|
42
|
+
userId: { type: "string" },
|
|
43
|
+
artifactId: { type: "string" },
|
|
44
|
+
threadId: { type: "string" },
|
|
45
|
+
version: { type: "integer", minimum: 1 },
|
|
46
|
+
mime: { type: "string" },
|
|
47
|
+
size: { type: "integer", minimum: 0 },
|
|
48
|
+
hash: { type: "string", pattern: "^[0-9a-f]{64}$" },
|
|
49
|
+
},
|
|
50
|
+
required: ["tenantId", "artifactId", "threadId", "version", "mime", "size", "hash"],
|
|
51
|
+
additionalProperties: false,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function artifactJson(ref: ArtifactBodyRef): JsonObject {
|
|
55
|
+
const tenantId = ref.tenantId;
|
|
56
|
+
const accountId = ref.accountId;
|
|
57
|
+
const userId = ref.userId;
|
|
58
|
+
return {
|
|
59
|
+
...(tenantId === undefined ? {} : { tenantId }),
|
|
60
|
+
...(accountId === undefined ? {} : { accountId }),
|
|
61
|
+
...(userId === undefined ? {} : { userId }),
|
|
62
|
+
artifactId: ref.artifactId,
|
|
63
|
+
threadId: ref.threadId,
|
|
64
|
+
version: ref.version,
|
|
65
|
+
mime: ref.mime,
|
|
66
|
+
size: ref.size,
|
|
67
|
+
hash: ref.hash,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function sourceCount(args: JsonObject): number {
|
|
72
|
+
return Number(args.filePath !== undefined) + Number(args.artifact !== undefined) + Number(args.sandboxPath !== undefined);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function fileLimit(options: WorkToolsOptions): number {
|
|
76
|
+
return resolveWorkLimits(options.limits).maxFileBytes;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function fileDraftPayload(
|
|
80
|
+
options: WorkToolsOptions,
|
|
81
|
+
provider: WorkProvider,
|
|
82
|
+
args: JsonObject,
|
|
83
|
+
context: ToolExecutionContext,
|
|
84
|
+
): Promise<JsonObject> {
|
|
85
|
+
if (sourceCount(args) !== 1) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "provide exactly one of filePath, artifact, or sandboxPath");
|
|
86
|
+
const maxBytes = fileLimit(options);
|
|
87
|
+
const { sandboxPath, ...payload } = args;
|
|
88
|
+
if (args.artifact !== undefined) {
|
|
89
|
+
const artifact = artifactRef(args.artifact);
|
|
90
|
+
if (artifact.size > maxBytes) throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "File exceeds byte limit");
|
|
91
|
+
if (provider === "microsoft365") reqString(args, "name");
|
|
92
|
+
return { ...payload, artifact: artifactJson(artifact), contentHash: artifact.hash, byteLength: artifact.size };
|
|
93
|
+
}
|
|
94
|
+
if (sandboxPath !== undefined) {
|
|
95
|
+
if (typeof sandboxPath !== "string" || !sandboxPath)
|
|
96
|
+
throw new WorkToolError("ERR_PRISM_WORK_INPUT", "sandboxPath must be a non-empty string");
|
|
97
|
+
if (!options.filesystem) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "sandboxPath requires a configured filesystem");
|
|
98
|
+
const filePath = await resolveSandboxPath(options.filesystem, sandboxPath);
|
|
99
|
+
const bytes = await options.filesystem.readFile(filePath, { maxBytes, signal: context.signal });
|
|
100
|
+
if (bytes.byteLength > maxBytes) throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "File exceeds byte limit");
|
|
101
|
+
const contentHash = sha256(bytes);
|
|
102
|
+
if (!options.artifacts) return { ...payload, filePath, contentHash, byteLength: bytes.byteLength };
|
|
103
|
+
const artifact = options.artifacts.createRef({
|
|
104
|
+
context,
|
|
105
|
+
provider,
|
|
106
|
+
mime: "application/octet-stream",
|
|
107
|
+
byteLength: bytes.byteLength,
|
|
108
|
+
contentHash,
|
|
109
|
+
});
|
|
110
|
+
await options.artifacts.bodies.put(artifact, bytes, { signal: context.signal });
|
|
111
|
+
if (provider === "microsoft365") reqString(args, "name");
|
|
112
|
+
return { ...payload, artifact: artifactJson(artifact), contentHash, byteLength: bytes.byteLength };
|
|
113
|
+
}
|
|
114
|
+
const source = await readUploadBytes(args, undefined, maxBytes, context.signal);
|
|
115
|
+
return { ...payload, contentHash: source.contentHash, byteLength: source.bytes.byteLength };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function fileGet(
|
|
119
|
+
options: WorkToolsOptions,
|
|
120
|
+
adapter: WorkAdapter,
|
|
121
|
+
provider: WorkProvider,
|
|
122
|
+
args: JsonObject,
|
|
123
|
+
context: ToolExecutionContext,
|
|
124
|
+
): Promise<JsonObject> {
|
|
125
|
+
const itemId = reqString(args, "id");
|
|
126
|
+
const destPath = optString(args, "destPath");
|
|
127
|
+
if (destPath === "") throw new WorkToolError("ERR_PRISM_WORK_INPUT", "destPath must be a non-empty string");
|
|
128
|
+
if (!destPath && !options.artifacts)
|
|
129
|
+
throw new WorkToolError("ERR_PRISM_WORK_INPUT", "file get requires destPath or a configured artifact store");
|
|
130
|
+
if (!options.scanAttachment) throw new WorkToolError("ERR_PRISM_WORK_POLICY", "file get requires an attachment scan");
|
|
131
|
+
const raw = await adapter.runOp("file.get" as never, { id: itemId }, context.signal);
|
|
132
|
+
if (!(raw instanceof Uint8Array)) throw new WorkToolError("ERR_PRISM_WORK_HTTP", "Connector file download was not bytes");
|
|
133
|
+
const maxBytes = fileLimit(options);
|
|
134
|
+
if (raw.byteLength > maxBytes) throw new WorkToolError("ERR_PRISM_WORK_LIMIT", "File exceeds byte limit");
|
|
135
|
+
await options.scanAttachment({ bytes: raw.byteLength, name: itemId });
|
|
136
|
+
const contentHash = sha256(raw);
|
|
137
|
+
const artifacts = options.artifacts;
|
|
138
|
+
const artifact = artifacts?.createRef({
|
|
139
|
+
context,
|
|
140
|
+
provider,
|
|
141
|
+
itemId,
|
|
142
|
+
mime: "application/octet-stream",
|
|
143
|
+
byteLength: raw.byteLength,
|
|
144
|
+
contentHash,
|
|
145
|
+
});
|
|
146
|
+
if (artifact && artifacts) await artifacts.bodies.put(artifact, raw, { signal: context.signal });
|
|
147
|
+
const path =
|
|
148
|
+
destPath === undefined
|
|
149
|
+
? undefined
|
|
150
|
+
: await (async () => {
|
|
151
|
+
if (!options.filesystem) throw new WorkToolError("ERR_PRISM_WORK_INPUT", "destPath requires a configured filesystem");
|
|
152
|
+
const target = await resolveSandboxPath(options.filesystem, destPath);
|
|
153
|
+
await options.filesystem.writeFile(target, raw, { maxBytes, signal: context.signal });
|
|
154
|
+
return target;
|
|
155
|
+
})();
|
|
156
|
+
return {
|
|
157
|
+
...(artifact === undefined ? {} : { artifact: artifactJson(artifact) }),
|
|
158
|
+
...(path === undefined ? {} : { path }),
|
|
159
|
+
byteLength: raw.byteLength,
|
|
160
|
+
contentHash,
|
|
161
|
+
untrusted: true,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function result(context: ToolExecutionContext, name: string, provider: WorkProvider, value: unknown): ToolResult {
|
|
166
|
+
// No banner here: the kernel wraps untrusted results (UNTRUSTED_EXTERNAL_TRUST) in its envelope.
|
|
167
|
+
return { toolCallId: context.toolCallId, name, value, metadata: { trust: UNTRUSTED_EXTERNAL_TRUST, provider } };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function splitAddresses(value: string): string[] {
|
|
171
|
+
return value
|
|
172
|
+
.split(",")
|
|
173
|
+
.map((part) => part.trim())
|
|
174
|
+
.filter(Boolean);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function assertExternalAllowed(options: WorkToolsOptions, addresses: readonly string[]): void {
|
|
178
|
+
const policy = options.externalRecipients;
|
|
179
|
+
for (const address of addresses) {
|
|
180
|
+
if (!policy?.allow(address)) {
|
|
181
|
+
throw new WorkToolError("ERR_PRISM_WORK_POLICY", `External recipient denied: ${address}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
type WorkAdapter = Microsoft365Adapter | GoogleWorkspaceAdapter;
|
|
187
|
+
|
|
188
|
+
export async function executeApprovedMutation(
|
|
189
|
+
options: WorkToolsOptions,
|
|
190
|
+
adapter: WorkAdapter,
|
|
191
|
+
op: string,
|
|
192
|
+
payload: JsonObject,
|
|
193
|
+
context: ToolExecutionContext,
|
|
194
|
+
): Promise<unknown> {
|
|
195
|
+
const draftId = typeof payload.draftId === "string" && payload.draftId.trim() ? payload.draftId.trim() : undefined;
|
|
196
|
+
const expectedRevision = typeof payload.revision === "number" ? payload.revision : undefined;
|
|
197
|
+
const { draftId: _d, revision: _r, idempotencyKey: _i, ...cleanPayload } = payload;
|
|
198
|
+
|
|
199
|
+
let draft: WorkDraft;
|
|
200
|
+
if (draftId) {
|
|
201
|
+
const existingRes = adapter.getDraft(draftId);
|
|
202
|
+
const existing = existingRes instanceof Promise ? await existingRes : existingRes;
|
|
203
|
+
if (!existing) {
|
|
204
|
+
throw new WorkToolError("ERR_PRISM_WORK_DRAFT", `Draft ${draftId} not found`);
|
|
205
|
+
}
|
|
206
|
+
if (existing.identityKey !== identityKey(adapter.identity)) {
|
|
207
|
+
throw new WorkToolError("ERR_PRISM_WORK_IDENTITY", "Draft identity mismatch");
|
|
208
|
+
}
|
|
209
|
+
if (expectedRevision !== undefined && existing.revision !== expectedRevision) {
|
|
210
|
+
throw new WorkToolError(
|
|
211
|
+
"ERR_PRISM_WORK_DRAFT_STALE",
|
|
212
|
+
`Draft revision mismatch (expected ${expectedRevision}, got ${existing.revision})`,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
if (existing.status === "executed") {
|
|
216
|
+
throw new WorkToolError("ERR_PRISM_WORK_DRAFT_EXECUTED", "Draft already executed");
|
|
217
|
+
}
|
|
218
|
+
if (existing.status === "unknown") {
|
|
219
|
+
throw new WorkToolError("ERR_PRISM_WORK_IDEMPOTENCY_UNKNOWN", "Draft outcome is unknown and requires reconciliation");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const hasKeys = Object.keys(cleanPayload).length > 0;
|
|
223
|
+
const mergedPayload: JsonObject = hasKeys ? { ...existing.payload, ...cleanPayload } : existing.payload;
|
|
224
|
+
const isModified = hasKeys && computePayloadDigest(mergedPayload) !== existing.payloadDigest;
|
|
225
|
+
|
|
226
|
+
if (isModified) {
|
|
227
|
+
const newRecipients = extractDraftRecipients(mergedPayload);
|
|
228
|
+
if (newRecipients.length > 0) {
|
|
229
|
+
assertExternalAllowed(options, newRecipients);
|
|
230
|
+
}
|
|
231
|
+
if (adapter.updateDraft) {
|
|
232
|
+
const updateRes = adapter.updateDraft(existing.draftId, mergedPayload, { expectedRevision: existing.revision });
|
|
233
|
+
draft = updateRes instanceof Promise ? await updateRes : updateRes;
|
|
234
|
+
} else {
|
|
235
|
+
const createRes = adapter.createDraft(op as never, mergedPayload);
|
|
236
|
+
draft = createRes instanceof Promise ? await createRes : createRes;
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
draft = existing;
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
const recipients = extractDraftRecipients(cleanPayload);
|
|
243
|
+
if (recipients.length > 0) {
|
|
244
|
+
assertExternalAllowed(options, recipients);
|
|
245
|
+
}
|
|
246
|
+
const createRes = adapter.createDraft(op as never, cleanPayload);
|
|
247
|
+
draft = createRes instanceof Promise ? await createRes : createRes;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let approved = false;
|
|
251
|
+
if (options.approval) {
|
|
252
|
+
const checkInput: WorkApprovalCheckInput = {
|
|
253
|
+
draftId: draft.draftId,
|
|
254
|
+
op,
|
|
255
|
+
identity: adapter.identity,
|
|
256
|
+
revision: draft.revision,
|
|
257
|
+
payloadDigest: draft.payloadDigest,
|
|
258
|
+
recipients: draft.recipients,
|
|
259
|
+
policyRevision: draft.policyRevision,
|
|
260
|
+
};
|
|
261
|
+
const decisionRes = options.approval.isApproved(checkInput);
|
|
262
|
+
const decision = decisionRes instanceof Promise ? await decisionRes : decisionRes;
|
|
263
|
+
if (decision === true) {
|
|
264
|
+
approved = true;
|
|
265
|
+
const approval: WorkDraftApproval = {
|
|
266
|
+
draftId: draft.draftId,
|
|
267
|
+
revision: draft.revision,
|
|
268
|
+
payloadDigest: draft.payloadDigest,
|
|
269
|
+
identityKey: draft.identityKey,
|
|
270
|
+
policyRevision: draft.policyRevision,
|
|
271
|
+
approvedAt: new Date().toISOString(),
|
|
272
|
+
};
|
|
273
|
+
if (adapter.approveDraft) {
|
|
274
|
+
const appRes = adapter.approveDraft(approval);
|
|
275
|
+
draft = appRes instanceof Promise ? await appRes : appRes;
|
|
276
|
+
} else {
|
|
277
|
+
const markRes = adapter.markDraft(draft.draftId, "approved");
|
|
278
|
+
draft = markRes instanceof Promise ? await markRes : markRes;
|
|
279
|
+
}
|
|
280
|
+
} else if (typeof decision === "object" && decision !== null) {
|
|
281
|
+
validateApproval(draft, decision, { policyRevision: draft.policyRevision });
|
|
282
|
+
approved = true;
|
|
283
|
+
if (adapter.approveDraft) {
|
|
284
|
+
const appRes = adapter.approveDraft(decision);
|
|
285
|
+
draft = appRes instanceof Promise ? await appRes : appRes;
|
|
286
|
+
} else {
|
|
287
|
+
const markRes = adapter.markDraft(draft.draftId, "approved");
|
|
288
|
+
draft = markRes instanceof Promise ? await markRes : markRes;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} else if (draft.status === "approved") {
|
|
292
|
+
approved = true;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!approved || draft.status !== "approved") {
|
|
296
|
+
return {
|
|
297
|
+
draftId: draft.draftId,
|
|
298
|
+
revision: draft.revision,
|
|
299
|
+
payloadDigest: draft.payloadDigest,
|
|
300
|
+
status: "pending_approval",
|
|
301
|
+
untrusted: true,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (draft.approval) {
|
|
306
|
+
validateApproval(draft, draft.approval, { policyRevision: draft.policyRevision });
|
|
307
|
+
}
|
|
308
|
+
assertIdentityActive(adapter.identity);
|
|
309
|
+
|
|
310
|
+
const idempotencyKey = context.idempotencyKey;
|
|
311
|
+
const store = options.idempotencyStore;
|
|
312
|
+
if (!idempotencyKey || !store) {
|
|
313
|
+
throw new WorkToolError("ERR_PRISM_WORK_IDEMPOTENCY", "approved mutation requires core idempotency key and store");
|
|
314
|
+
}
|
|
315
|
+
const claim = await store.begin({ identity: adapter.identity, key: idempotencyKey, op, signal: context.signal });
|
|
316
|
+
if (claim.outcome === "existing") return existingMutationResult(claim.record);
|
|
317
|
+
|
|
318
|
+
let result: { draftId: string; revision: number; resourceId?: string };
|
|
319
|
+
try {
|
|
320
|
+
const markAppRes = adapter.markDraft(draft.draftId, "approved");
|
|
321
|
+
draft = markAppRes instanceof Promise ? await markAppRes : markAppRes;
|
|
322
|
+
const value = await adapter.runOp(op as never, draft.payload, context.signal);
|
|
323
|
+
const markExecRes = adapter.markDraft(draft.draftId, "executed");
|
|
324
|
+
draft = markExecRes instanceof Promise ? await markExecRes : markExecRes;
|
|
325
|
+
result = {
|
|
326
|
+
draftId: draft.draftId,
|
|
327
|
+
revision: draft.revision,
|
|
328
|
+
...(typeof (value as { id?: string })?.id === "string" ? { resourceId: (value as { id: string }).id } : {}),
|
|
329
|
+
};
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (claim.record.claimToken) {
|
|
332
|
+
const input = {
|
|
333
|
+
identity: adapter.identity,
|
|
334
|
+
key: idempotencyKey,
|
|
335
|
+
op,
|
|
336
|
+
claimToken: claim.record.claimToken,
|
|
337
|
+
expectedVersion: claim.record.version,
|
|
338
|
+
};
|
|
339
|
+
const failure = classifiedFailure(error);
|
|
340
|
+
if (failure) {
|
|
341
|
+
await store.fail({ ...input, ...failure });
|
|
342
|
+
} else {
|
|
343
|
+
await store.markUnknown({ ...input, failure: { code: "ERR_PRISM_WORK_IDEMPOTENCY_UNKNOWN" } });
|
|
344
|
+
try {
|
|
345
|
+
const markUnkRes = adapter.markDraft(draft.draftId, "unknown");
|
|
346
|
+
if (markUnkRes instanceof Promise) await markUnkRes;
|
|
347
|
+
} catch {
|
|
348
|
+
// ignore draft mark error
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
if (claim.record.claimToken) {
|
|
355
|
+
await store.complete({
|
|
356
|
+
identity: adapter.identity,
|
|
357
|
+
key: idempotencyKey!,
|
|
358
|
+
op,
|
|
359
|
+
claimToken: claim.record.claimToken,
|
|
360
|
+
expectedVersion: claim.record.version,
|
|
361
|
+
result: {
|
|
362
|
+
draftId: result.draftId,
|
|
363
|
+
...(result.resourceId ? { resourceId: result.resourceId } : {}),
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return { ...result, status: "executed", untrusted: true as const };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function existingMutationResult(record: WorkMutationRecord): {
|
|
371
|
+
readonly draftId: string;
|
|
372
|
+
readonly resourceId?: string;
|
|
373
|
+
readonly status: "duplicate";
|
|
374
|
+
readonly untrusted: true;
|
|
375
|
+
} {
|
|
376
|
+
if (record.status === "completed" && record.result) {
|
|
377
|
+
return { ...record.result, status: "duplicate", untrusted: true };
|
|
378
|
+
}
|
|
379
|
+
if (record.status === "unknown") {
|
|
380
|
+
throw new WorkToolError("ERR_PRISM_WORK_IDEMPOTENCY_UNKNOWN", "mutation outcome requires reconciliation");
|
|
381
|
+
}
|
|
382
|
+
throw new WorkToolError("ERR_PRISM_WORK_IDEMPOTENCY", "mutation is not available for replay");
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function classifiedFailure(
|
|
386
|
+
error: unknown,
|
|
387
|
+
): { readonly status: "failed_retryable" | "failed_terminal"; readonly failure: { readonly code: string } } | undefined {
|
|
388
|
+
if (!(error instanceof WorkToolError)) return undefined;
|
|
389
|
+
if (error.code === "ERR_PRISM_WORK_CREDENTIAL") return { status: "failed_retryable", failure: { code: error.code } };
|
|
390
|
+
if (error.code === "ERR_PRISM_WORK_INPUT" || error.code === "ERR_PRISM_WORK_POLICY" || error.code === "ERR_PRISM_WORK_LIMIT") {
|
|
391
|
+
return { status: "failed_terminal", failure: { code: error.code } };
|
|
392
|
+
}
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export function pushTool(tools: ToolDefinition[], tool: ToolDefinition): void {
|
|
397
|
+
tools.push(tool);
|
|
398
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ToolDefinition, type ToolEffectDeclaration } from "@arnilo/prism";
|
|
2
|
+
import { pushGwsTools } from "./gws-tools.js";
|
|
3
|
+
import { pushM365Tools } from "./m365-tools.js";
|
|
4
|
+
import type { WorkToolsOptions } from "./types.js";
|
|
5
|
+
|
|
6
|
+
const WORK_OBSERVATION_EFFECT = { kind: "none", idempotency: "none" } as const satisfies ToolEffectDeclaration;
|
|
7
|
+
const WORK_MUTATION_EFFECT = { kind: "external_mutation", idempotency: "tool_managed" } as const satisfies ToolEffectDeclaration;
|
|
8
|
+
const NETWORK_EFFECTS = ["network"] as const;
|
|
9
|
+
const NETWORK_EXTERNAL_EFFECTS = ["network", "external"] as const;
|
|
10
|
+
/** Connector writes; the rest of the group only reads. Exported so the package can assert coverage. */
|
|
11
|
+
export const WORK_MUTATING_TOOL_NAMES: ReadonlySet<string> = new Set([
|
|
12
|
+
"m365_mail_draft_send",
|
|
13
|
+
"m365_calendar_draft_add",
|
|
14
|
+
"m365_file_draft_upload",
|
|
15
|
+
"m365_file_draft_copy",
|
|
16
|
+
"m365_file_draft_share",
|
|
17
|
+
"m365_todo_draft_add",
|
|
18
|
+
"m365_todo_draft_complete",
|
|
19
|
+
"gws_mail_draft_send",
|
|
20
|
+
"gws_calendar_draft_add",
|
|
21
|
+
"gws_file_draft_upload",
|
|
22
|
+
"gws_file_draft_share",
|
|
23
|
+
"gws_task_draft_add",
|
|
24
|
+
"gws_task_draft_complete",
|
|
25
|
+
"gws_docs_draft_create",
|
|
26
|
+
"gws_docs_draft_update",
|
|
27
|
+
"gws_sheets_draft_create",
|
|
28
|
+
"gws_sheets_draft_update",
|
|
29
|
+
"gws_slides_draft_create",
|
|
30
|
+
"gws_slides_draft_update",
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
export function createWorkTools(options: WorkToolsOptions): readonly ToolDefinition[] {
|
|
34
|
+
const tools: ToolDefinition[] = [];
|
|
35
|
+
if (options.microsoft365) pushM365Tools(tools, options, options.microsoft365);
|
|
36
|
+
if (options.googleWorkspace) pushGwsTools(tools, options, options.googleWorkspace);
|
|
37
|
+
return tools.map((tool) => ({
|
|
38
|
+
...tool,
|
|
39
|
+
effect: WORK_MUTATING_TOOL_NAMES.has(tool.name) ? WORK_MUTATION_EFFECT : WORK_OBSERVATION_EFFECT,
|
|
40
|
+
effects: WORK_MUTATING_TOOL_NAMES.has(tool.name) ? NETWORK_EXTERNAL_EFFECTS : NETWORK_EFFECTS,
|
|
41
|
+
}));
|
|
42
|
+
}
|