Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 28 additions & 34 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/argent-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"picocolors": "^1.1.1"
},
"devDependencies": {
"@argent/artifacts": "file:../artifacts",
"@types/node": "^26.0.1",
"typescript": "^6.0.3",
"vitest": "^4.1.9"
Expand Down
5 changes: 4 additions & 1 deletion packages/argent-cli/test/run-artifacts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { join } from "node:path";
import { tmpdir } from "node:os";
import { mkdtemp, rm, writeFile, stat } from "node:fs/promises";
import { run, type RunCommandOptions } from "../src/run.js";
import { ARTIFACT_MARKER, artifactsRoot, type ArtifactHandle } from "@argent/tools-client";
import { artifactsRoot } from "@argent/tools-client";
import { ARTIFACT_MARKER, type ArtifactHandle } from "@argent/artifacts";

const PNG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x11, 0x22, 0x33]);

Expand Down Expand Up @@ -129,6 +130,7 @@ describe("CLI run — artifact materialization end-to-end", () => {
return {
[ARTIFACT_MARKER]: true,
id: "loc-1",
kind: "screenshot",
filename: "shot.png",
mimeType: "image/png",
size: st.size,
Expand Down Expand Up @@ -159,6 +161,7 @@ describe("CLI run — artifact materialization end-to-end", () => {
image: {
[ARTIFACT_MARKER]: true,
id: "rem-1",
kind: "screenshot",
filename: "shot.png",
mimeType: "image/png",
size: PNG.length,
Expand Down
1 change: 1 addition & 0 deletions packages/argent-mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@modelcontextprotocol/sdk": "^1.29.0"
},
"devDependencies": {
"@argent/artifacts": "file:../artifacts",
"@types/node": "^26.0.1",
"typescript": "^6.0.3",
"vitest": "^4.1.9"
Expand Down
13 changes: 11 additions & 2 deletions packages/argent-mcp/test/content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,21 @@ import {
flowRunToMcpContent,
type FlowExecuteResult,
} from "../src/content.js";
import { ARTIFACT_MARKER, type ArtifactHandle } from "@argent/tools-client";
import { ARTIFACT_MARKER, type ArtifactHandle, type ArtifactKind } from "@argent/artifacts";

const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];

function artifactKind(filename: string, mimeType: string): ArtifactKind {
if (mimeType.startsWith("image/")) return "screenshot";
if (filename.includes("cpu")) return "native-profile-cpu";
if (filename.includes("hangs")) return "native-profile-hangs";
if (filename.includes("leaks")) return "native-profile-leaks";
return "native-profile-trace";
}

function artifactHandle(id: string, filename: string, mimeType: string): ArtifactHandle {
return { [ARTIFACT_MARKER]: true, id, filename, mimeType, size: 0 };
const kind = artifactKind(filename, mimeType);
return { [ARTIFACT_MARKER]: true, id, kind, filename, mimeType, size: 0 };
}

function fetchReturning(bytes: number[]): typeof fetch {
Expand Down
3 changes: 3 additions & 0 deletions packages/argent-tools-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
"test": "vitest run",
"typecheck:tests": "tsc --noEmit -p tsconfig.test.json"
},
"dependencies": {
"@argent/artifacts": "file:../artifacts"
},
"devDependencies": {
"@types/node": "^26.0.1",
"typescript": "^6.0.3",
Expand Down
29 changes: 1 addition & 28 deletions packages/argent-tools-client/src/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,37 +33,10 @@ import { basename, join } from "node:path";
import { createHash } from "node:crypto";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { ARTIFACT_MARKER, type ArtifactHandle } from "@argent/artifacts";

const execFileAsync = promisify(execFile);

/** Must match the tool-server's wire contract (`tool-server/src/artifacts.ts`). */
export const ARTIFACT_MARKER = "__argentArtifact" as const;

export interface ArtifactHandle {
[ARTIFACT_MARKER]: true;
id: string;
filename: string;
mimeType: string;
size: number;
/**
* Absolute path of the file on the tool-server host. When the tool-server is
* co-located with this client, the file is already on disk here — the gate
* reads it directly instead of downloading it over `/artifacts/:id`, avoiding
* a redundant second copy. Verified against {@link size}/{@link mtimeMs}
* before it is trusted; any mismatch (or a remote host) falls back to the
* download path. Absent on older tool-servers that don't emit it.
*/
hostPath?: string;
/** mtime of {@link hostPath} (ms) at registration, for the integrity check. */
mtimeMs?: number;
/**
* Present when the artifact is a directory bundle (e.g. an Instruments
* `.trace`). Locally the gate uses the directory in place; on a remote miss
* the download is a gzipped tar that the client unpacks back into a directory.
*/
archive?: "tar.gz";
}

export function isArtifactHandle(value: unknown): value is ArtifactHandle {
return (
!!value &&
Expand Down
3 changes: 1 addition & 2 deletions packages/argent-tools-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,10 @@ export {
isArtifactHandle,
getDeviceIdFromArgs,
artifactsRoot,
ARTIFACT_MARKER,
type ArtifactHandle,
type MaterializeContext,
type MaterializedImage,
} from "./artifacts.js";
export type { ArtifactHandle } from "@argent/artifacts";

export {
prepareFileInputs,
Expand Down
2 changes: 2 additions & 0 deletions packages/argent-tools-client/src/tools-client.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { ensureToolsServer, type ToolsServerHandle, type ToolsServerPaths } from "./launcher.js";
import { getResolvedToolsUrl } from "./link-config.js";
import { prepareFileInputs, applyClientFileDirectives, type FileInputSpec } from "./file-inputs.js";
import type { ArtifactOutputMap } from "@argent/artifacts";

export interface ToolMeta {
name: string;
description: string;
inputSchema: Record<string, unknown>;
outputHint?: string;
artifacts?: ArtifactOutputMap;
/** Args that name files on the CALLER's machine — see file-inputs.ts. */
fileInputs?: FileInputSpec[];
alwaysLoad?: boolean;
Expand Down
19 changes: 16 additions & 3 deletions packages/argent-tools-client/test/artifacts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,20 @@ import {
isArtifactHandle,
getDeviceIdFromArgs,
artifactDir,
ARTIFACT_MARKER,
type ArtifactHandle,
} from "../src/artifacts.js";
import { ARTIFACT_MARKER, type ArtifactHandle, type ArtifactKind } from "@argent/artifacts";

function artifactKind(filename: string, mimeType: string): ArtifactKind {
if (mimeType.startsWith("image/")) return "screenshot";
if (filename.includes("cpu")) return "native-profile-cpu";
if (filename.includes("hangs")) return "native-profile-hangs";
if (filename.includes("leaks")) return "native-profile-leaks";
return "native-profile-trace";
}

function handle(id: string, filename: string, mimeType: string): ArtifactHandle {
return { [ARTIFACT_MARKER]: true, id, filename, mimeType, size: 0 };
const kind = artifactKind(filename, mimeType);
return { [ARTIFACT_MARKER]: true, id, kind, filename, mimeType, size: 0 };
}

const PNG = [0x89, 0x50, 0x4e, 0x47, 0x01, 0x02];
Expand Down Expand Up @@ -141,6 +149,7 @@ describe("materializeArtifacts", () => {
const h: ArtifactHandle = {
[ARTIFACT_MARKER]: true,
id: "trunc",
kind: "native-profile-cpu",
filename: "data.xml",
mimeType: "application/xml",
size: 99, // server announced 99 bytes…
Expand Down Expand Up @@ -190,6 +199,7 @@ describe("materializeArtifacts local short-circuit", () => {
return {
[ARTIFACT_MARKER]: true,
id,
kind: artifactKind(filename, mimeType),
filename,
mimeType,
size: st.size,
Expand Down Expand Up @@ -237,6 +247,7 @@ describe("materializeArtifacts local short-circuit", () => {
const h: ArtifactHandle = {
[ARTIFACT_MARKER]: true,
id: "img2",
kind: "screenshot",
filename: "shot.png",
mimeType: "image/png",
size: PNG.length,
Expand All @@ -258,6 +269,7 @@ describe("materializeArtifacts local short-circuit", () => {
const h: ArtifactHandle = {
[ARTIFACT_MARKER]: true,
id: "img3",
kind: "screenshot",
filename: "shot.png",
mimeType: "image/png",
size: PNG.length,
Expand Down Expand Up @@ -320,6 +332,7 @@ describe("materializeArtifacts directory bundles", () => {
return {
[ARTIFACT_MARKER]: true,
id,
kind: "native-profile-trace",
filename: "session.trace",
mimeType: "application/octet-stream",
size: 0,
Expand Down
Loading
Loading