#I've been working on the blueprint

1 messages Β· Page 1 of 1 (latest)

honest pebble
#

I’m picking up a wedding suit atm but will be back at 2pm PT to help sync

#

Otherwise happy to help async

errant locust
#

No rush, thanks! Kind of hoping that you'll be wearing the wedding suit while helping me πŸ˜›

#

Im trying to coax Zed+Claude into figuring it out

honest pebble
#

I'm around now!

errant locust
#

basically you can do eg.

dagger init --blueprint=github.com/shykes/x/go

# load functions from the blueprint module...
dagger functions

# ... but execute them in the context of the current module
dagger call build
#

But there's a problem when loading the module. You can repro with:

dagger -m github.com/shykes/dagger@module-blueprint <<.
  dev |
  with-exec -- dagger init --blueprint=github.com/shykes/x/go |
  with-exec dagger functions |
  stdout
.

dagger functions fails with:

Error: main object not found, check that your module's name and main object match
#

It makes sense that there would be issues related to the module name: when loading a module that references a blueprint, you get the types from one module, and the name from the other. That's probably where the mismatch comes from, I think?

craggy breach
honest pebble
# errant locust But there's a problem when loading the module. You can repro with: ``` dagger -...

Yeah, you can actually avoid it by running this instead:

dagger -m github.com/shykes/dagger@module-blueprint <<.
  dev |
  with-exec -- dagger init --blueprint=github.com/shykes/x/go --name=go |
  with-exec dagger functions |
  stdout
.

(diff being the additional --name=go)

The CLI is looking for an object with the same name as the module itself. Since in your failing example you are getting the default module name (happens to be mnt in this case cause that is the name of the dir you are in), it's looking for an object named Mnt but can't find it and errors out. That's why specifying --name=go avoids the error; there now is an object named Go which gets found.

#

If we don't want that restriction for whatever reason, we could most likely update the CLI to handle this case where there's a blueprint and look for an object with the name of the blueprint rather than the name of the module in that particular case

errant locust
#

(otherwise it would be weird, imagine 50 dagger modules for 50 go apps, using a blueprint module called "go", and all 50 modules are called "go")

errant locust
#

OK I changed the target module name to the blueprint name as a workaround.. works fine... but... there was a worse bug hiding.

#

Functions are still executed in the context dir of the upstream blueprint module 😭

#

I could use some guidance on the correct hook points here... Claude was very confident but... it seems that it was wrong

#

Poking around but no idea how to solve it

errant locust
#

@honest pebble any chance I can bug you for a few minutes after the demo call? πŸ™ I'd really like to get the PR ready for review before the week-end

honest pebble
#

Seeing what's possible in terms of fixing

errant locust
#

BTW I've been thinking about the module name question from before... I think having the blueprint name used everywhere might have undesirable consequences, like for example telemetry might show everything under the blueprint's module name, so if 100 modules use a given module, all the telemetry from running those 100 modules will show as the blueprint running it instead.

#

(but still a less urgent problem than the context dir one)

honest pebble
#

This fixes it:

diff --git a/core/modfunc.go b/core/modfunc.go
index 662517d44..8543c284e 100644
--- a/core/modfunc.go
+++ b/core/modfunc.go
@@ -635,7 +635,7 @@ func (fn *ModuleFunction) loadContextualArg(
        case "Directory":
                slog.Debug("moduleFunction.loadContextualArg: loading contextual directory", "fn", arg.Name, "dir", arg.DefaultPath)
 
-               dir, err := fn.mod.Source.Self().LoadContext(ctx, dag, arg.DefaultPath, arg.Ignore)
+               dir, err := fn.mod.ContextSource.Self().LoadContext(ctx, dag, arg.DefaultPath, arg.Ignore)
                if err != nil {
                        return nil, fmt.Errorf("failed to load contextual directory %q: %w", arg.DefaultPath, err)
                }
@@ -649,7 +649,7 @@ func (fn *ModuleFunction) loadContextualArg(
                filePath := filepath.Base(arg.DefaultPath)
 
                // Load the directory containing the file.
-               dir, err := fn.mod.Source.Self().LoadContext(ctx, dag, dirPath, nil)
+               dir, err := fn.mod.ContextSource.Self().LoadContext(ctx, dag, dirPath, nil)
                if err != nil {
                        return nil, fmt.Errorf("failed to load contextual directory %q: %w", dirPath, err)
                }
diff --git a/core/module.go b/core/module.go
index 4548aeb6c..961dc1973 100644
--- a/core/module.go
+++ b/core/module.go
@@ -22,6 +22,9 @@ type Module struct {
        // The source of the module
        Source dagql.ObjectResult[*ModuleSource] `field:"true" name:"source" doc:"The source for the module."`
 
+       // The source to load contextual dirs/files from, which may be different than Source for blueprints
+       ContextSource dagql.ObjectResult[*ModuleSource]
+
        // The name of the module
        NameField string `field:"true" name:"name" doc:"The name of the module"`
 
diff --git a/core/schema/modulesource.go b/core/schema/modulesource.go
index ed4166f56..4ee4e3d0d 100644
--- a/core/schema/modulesource.go
+++ b/core/schema/modulesource.go
@@ -2241,13 +2241,12 @@ func (s *moduleSourceSchema) moduleSourceAsModule(
        var blueprintSrc dagql.ObjectResult[*core.ModuleSource]
        var targetName string
        var targetOriginalName string
-       var targetContextDir dagql.ObjectResult[*core.Directory]
+       originalSrc := src
 
        if src.Self().Blueprint.Self() != nil {
                // Store target module information
                targetName = src.Self().ModuleName
                targetOriginalName = src.Self().ModuleOriginalName
-               targetContextDir = src.Self().ContextDirectory
 
                // Use blueprint for SDK operations
                blueprintSrc = src.Self().Blueprint
@@ -2261,7 +2260,8 @@ func (s *moduleSourceSchema) moduleSourceAsModule(
 
        // Create module with blueprint source for SDK operations
        mod := &core.Module{
-               Source: src,
+               Source:        src,
+               ContextSource: originalSrc,
 
                NameField:    src.Self().ModuleName,
                OriginalName: src.Self().ModuleOriginalName,
@@ -2322,7 +2322,6 @@ func (s *moduleSourceSchema) moduleSourceAsModule(
 
        // If using a blueprint, restore target context and name for file operations
        if blueprintSrc.Self() != nil {
-               mod.Source.Self().ContextDirectory = targetContextDir
                mod.NameField = targetName
                mod.OriginalName = targetOriginalName
                // Use the target's module name for the final result

Basically just track which source to load context from separately. @errant locust you good with me just pushing that to the PR?

errant locust
#

yes please!

honest pebble
errant locust
#

the worst part is that I think Claude correctly made a plan to do this, but then just... didn't

honest pebble
#

I don't think there's many "strongly-typed DAG execution engines" in its training data πŸ˜… It oscillates between brilliance and bone-headedness when I use it on the engine codebase

honest pebble
errant locust
#

@honest pebble do you think there's an easy fix for the name thing?

honest pebble
# errant locust <@949034677610643507> do you think there's an easy fix for the name thing?

The name that's presented to callers should just be mapped from "underlying blueprint name" -> "wrapped name". There's needs to be a translation layer internally though because the module runtime needs to know what's actually being invoked.

This feels very similar to the existing support for renaming a dependency, I need to refresh my memory on how/where that happens though. I'll check and see if we can just re-use that

errant locust
#

I was naively thinking: if I change the module's name, I can also just rename that module's main module, and everything should still work...

honest pebble
errant locust
#

confirming that your fix works! party_blob

#

I'll push my own last little fix with the name override, then open the PR for real

#

thank you πŸ™

honest pebble
errant locust
#

Oh! interesting

#

This is because OriginalName is what the CLI introspection happens to use?

#

Oh, I'll need to change dagger update so that it also updates the blueprint

#

(either that or I remove the pinning feature for the blueprint... but that seems like a more controversial change)

honest pebble
# errant locust This is because `OriginalName` is what the CLI introspection happens to use?

Sort of the opposite actually. OriginalName is mostly only used internally and handles the case where the name presented to callers differs from what the module think its name is. The Name is what's presented to callers and OriginalName is used internally when actually invoking the runtime.

So as long as Name is what you want presented (i.e. the name of the wrapper module) and OriginalName is the real underlying blueprint name, it should work (🀞)

errant locust
#

@honest pebble what's a good way to check if name was correctly set?

honest pebble
#

probably the most direct way

errant locust
#

Oh there's also the prompt in the shell! It works πŸ™‚

#

OK everything seems to work. Thanks again

honest pebble
#

no problem, happy to help!