Ask implements [hooks.ModelClient]. Errors from any stage (model spec parsing, provider construction, stream open, stream recv) are returned unwrapped so the executor's fail-closed semantics deny PreToolUse calls cleanly. The caller (the model handler) is responsible for surfacing the error to the
( ctx context.Context, modelSpec, system, user string, schema *latest.StructuredOutput, )
| 36 | // (the model handler) is responsible for surfacing the error to the |
| 37 | // hook's [HandlerResult]. |
| 38 | func (c providerModelClient) Ask( |
| 39 | ctx context.Context, |
| 40 | modelSpec, system, user string, |
| 41 | schema *latest.StructuredOutput, |
| 42 | ) (string, error) { |
| 43 | cfg, err := latest.ParseModelRef(modelSpec) |
| 44 | if err != nil { |
| 45 | return "", fmt.Errorf("invalid model spec: %w", err) |
| 46 | } |
| 47 | |
| 48 | var opts []options.Opt |
| 49 | if schema != nil { |
| 50 | opts = append(opts, options.WithStructuredOutput(schema)) |
| 51 | } |
| 52 | registry := c.registry |
| 53 | if registry == nil { |
| 54 | registry = provider.DefaultRegistry() |
| 55 | } |
| 56 | p, err := registry.New(ctx, &cfg, environment.NewDefaultProvider(), opts...) |
| 57 | if err != nil { |
| 58 | return "", fmt.Errorf("create provider: %w", err) |
| 59 | } |
| 60 | |
| 61 | stream, err := p.CreateChatCompletionStream(ctx, []chat.Message{ |
| 62 | {Role: chat.MessageRoleSystem, Content: system}, |
| 63 | {Role: chat.MessageRoleUser, Content: user}, |
| 64 | }, nil) |
| 65 | if err != nil { |
| 66 | return "", fmt.Errorf("start stream: %w", err) |
| 67 | } |
| 68 | defer stream.Close() |
| 69 | |
| 70 | var sb strings.Builder |
| 71 | for { |
| 72 | resp, err := stream.Recv() |
| 73 | if errors.Is(err, io.EOF) { |
| 74 | break |
| 75 | } |
| 76 | if err != nil { |
| 77 | return "", fmt.Errorf("stream recv: %w", err) |
| 78 | } |
| 79 | for _, c := range resp.Choices { |
| 80 | sb.WriteString(c.Delta.Content) |
| 81 | } |
| 82 | } |
| 83 | return sb.String(), nil |
| 84 | } |
| 85 | |
| 86 | // registerModelHook installs the [hooks.HookTypeModel] factory on r |
| 87 | // using the runtime's default [hooks.ModelClient]. It is called once |
nothing calls this directly
no test coverage detected