#Export from LLM workspace to host

1 messages · Page 1 of 1 (latest)

ornate copper
#

Hi, I'm struggling to figure out why exporting files/directories from a workspace of an LLM instance seems to be not working. This is a the dagger module I have (where builderWorkspace is similar to the toyWorkspace example, with read/write tools):

  @func()
  async exportTest(repository: Directory): Promise<Container> {
    const workspace = dag.builderWorkspace(repository);
    let llm = dag
      .llm()
      .withBuilderWorkspace(workspace)
      .withPrompt("Write the text `Hello world` to `/hello.txt`");

    const content = await llm.builderWorkspace().container().file("/hello.txt").contents();
    console.log("Verifying the content of hello.txt: ", content);

    await llm.builderWorkspace().container().file("/hello.txt").export("./hello.txt");
    console.log("The above line seems to not work");

    // returning the container just for debugging purposes
    return llm.builderWorkspace().container();
  }

The export line seems to not do anything whether I call export-test from the interactive terminal or directly from shell. This is the output from a shell run:

❯ dagger call --progress plain export-test --repository .
<omitted irrelevant output>
116 : File.export(path: "./hello.txt"): String!
117 : │ export file /hello.txt to host ./hello.txt
117 : │ export file /hello.txt to host ./hello.txt DONE [0.0s]
116 : File.export DONE [0.0s]

115 : Container.file DONE [0.1s]

118 : File.contents: String!
118 : [0.0s] | Hello world
118 : File.contents DONE [0.0s]

90  : ForgeBuildAgent.exportTest(
90  : │ │ repository: Host.directory(include: ["./dagger.json", "./**/*"], path: "/Users/jet/Development/forge"): Directory!
90  : │ ): Container!
90  : [8.4s] | Verifying the content of hello.txt:  Hello world
90  : [8.4s] | The above line seems to not work
90  : ForgeBuildAgent.exportTest DONE [8.5s]

Am I exporting the file to the dagger runtime container or the LLM container, instead of host? Appreciate any pointers and help! Thank you!

#

Additionally, what's weird is that, if I make a chained call from the interactive terminal, like so

✔ export-test . | file /hello.txt | export ./hello.txt

It does actually work as expected and I will see hello.txt on my host file system, even though the above call from terminal should be exactly equivalent to llm.builderWorkspace().container().file("/hello.txt").export("./hello.txt"), right?

tame flame
#

Hi @ornate copper , it's actually not a LLM-specific issue, but a normal (but sometimes confusing) side effect of module sandboxing.

When you write a Dagger Module, all your module's functions are executed in a strict sandbox, that forbids access to the caller's true environment, including its host system. Instead, when you call host, the function accesses its own environment. And since it's running inside a container... The host system is that container. So export() actually exports to your function's ephemeral filesystem.

ornate copper
#

ahhh, got it! i was suspecting that's the case. what would you recommend as the best way if my goal is to export files produced by LLM onto my host system then?

tame flame
#

the recommended pattern is to have your function return a directory, then the caller can decide to export or not. If the caller is the CLI, then it might be:

your-function | export ./dest
#

You don't need to return the container for debugging purposes really, because for debugging you can:

  1. Call with dagger -i, then get an interactive shell at the moment of failure

or

  1. Inject .terminal() calls in your container for temporary debugging
ornate copper
#

ohhh, this^ helps a lot too, was not aware of this capability

#

the files need to be further processed by other containers/workflows, so i was just at a point of needing to inspect these files being reasonable before writing more downstream code, but it was really annoying to get to look at them, i could potentially just pass around the content for now

#

and eventually, i will want to just have a typescript script CLI that use my module and connect from @dagger.io/dagger, at that point, my understanding is that it should be flexible to just use fs:writeFile to write files to wherever needed. does that seem right?

tame flame
#

if the function returns a Directory or File, you can inject debugging in the terminal also

#

for a directory, you can call terminal against it also, and you get an interactive shell with the directory mounted

#

for file you can call contents, digest or export from the shell, that works well also

tame flame
#

If your file is very large, export is probably safer

ornate copper
#

perfect! thanks for the help!

glad plover
#

I try to do this exact command, but I cant see any changes goes to the host.

my-func "add new ec2 instance" | export --path "./"

I do see the output suggesting that it creates the desired terraform file, but when the command is done, there's no new file / modified file on the host.